Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 class SsaFunctionCompiler implements FunctionCompiler { | 7 class SsaFunctionCompiler implements FunctionCompiler { |
| 8 SsaCodeGeneratorTask generator; | 8 SsaCodeGeneratorTask generator; |
| 9 SsaBuilderTask builder; | 9 SsaBuilderTask builder; |
| 10 SsaOptimizerTask optimizer; | 10 SsaOptimizerTask optimizer; |
| (...skipping 1279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1290 } | 1290 } |
| 1291 return compiledArguments; | 1291 return compiledArguments; |
| 1292 } | 1292 } |
| 1293 | 1293 |
| 1294 /** | 1294 /** |
| 1295 * Try to inline [element] within the currect context of the builder. The | 1295 * Try to inline [element] within the currect context of the builder. The |
| 1296 * insertion point is the state of the builder. | 1296 * insertion point is the state of the builder. |
| 1297 */ | 1297 */ |
| 1298 bool tryInlineMethod(Element element, | 1298 bool tryInlineMethod(Element element, |
| 1299 Selector selector, | 1299 Selector selector, |
| 1300 TypeMask mask, | |
| 1300 List<HInstruction> providedArguments, | 1301 List<HInstruction> providedArguments, |
| 1301 ast.Node currentNode, | 1302 ast.Node currentNode, |
| 1302 {InterfaceType instanceType}) { | 1303 {InterfaceType instanceType}) { |
| 1303 // TODO(johnniwinther): Register this on the [registry]. Currently the | 1304 // TODO(johnniwinther): Register this on the [registry]. Currently the |
| 1304 // [CodegenRegistry] calls the enqueuer, but [element] should _not_ be | 1305 // [CodegenRegistry] calls the enqueuer, but [element] should _not_ be |
| 1305 // enqueued. | 1306 // enqueued. |
| 1306 backend.registerStaticUse(element, compiler.enqueuer.codegen); | 1307 backend.registerStaticUse(element, compiler.enqueuer.codegen); |
| 1307 | 1308 |
| 1308 // Ensure that [element] is an implementation element. | 1309 // Ensure that [element] is an implementation element. |
| 1309 element = element.implementation; | 1310 element = element.implementation; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1321 | 1322 |
| 1322 bool meetsHardConstraints() { | 1323 bool meetsHardConstraints() { |
| 1323 if (compiler.disableInlining) return false; | 1324 if (compiler.disableInlining) return false; |
| 1324 | 1325 |
| 1325 assert(invariant( | 1326 assert(invariant( |
| 1326 currentNode != null ? currentNode : element, | 1327 currentNode != null ? currentNode : element, |
| 1327 selector != null || | 1328 selector != null || |
| 1328 Elements.isStaticOrTopLevel(element) || | 1329 Elements.isStaticOrTopLevel(element) || |
| 1329 element.isGenerativeConstructorBody, | 1330 element.isGenerativeConstructorBody, |
| 1330 message: "Missing selector for inlining of $element.")); | 1331 message: "Missing selector for inlining of $element.")); |
| 1331 if (selector != null && !selector.applies(function, compiler.world)) { | 1332 if (selector != null) { |
| 1332 return false; | 1333 if (!selector.applies(function, compiler.world)) return false; |
| 1334 if (mask != null && !mask.canHit(function, selector, compiler.world)) { | |
| 1335 return false; | |
| 1336 } | |
| 1333 } | 1337 } |
| 1334 | 1338 |
| 1335 // Don't inline operator== methods if the parameter can be null. | 1339 // Don't inline operator== methods if the parameter can be null. |
| 1336 if (element.name == '==') { | 1340 if (element.name == '==') { |
| 1337 if (element.enclosingClass != compiler.objectClass | 1341 if (element.enclosingClass != compiler.objectClass |
| 1338 && providedArguments[1].canBeNull()) { | 1342 && providedArguments[1].canBeNull()) { |
| 1339 return false; | 1343 return false; |
| 1340 } | 1344 } |
| 1341 } | 1345 } |
| 1342 | 1346 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1441 } else { | 1445 } else { |
| 1442 backend.inlineCache.markAsNonInlinable(element, insideLoop: insideLoop); | 1446 backend.inlineCache.markAsNonInlinable(element, insideLoop: insideLoop); |
| 1443 } | 1447 } |
| 1444 return canInline; | 1448 return canInline; |
| 1445 } | 1449 } |
| 1446 | 1450 |
| 1447 void doInlining() { | 1451 void doInlining() { |
| 1448 // Add an explicit null check on the receiver before doing the | 1452 // Add an explicit null check on the receiver before doing the |
| 1449 // inlining. We use [element] to get the same name in the | 1453 // inlining. We use [element] to get the same name in the |
| 1450 // NoSuchMethodError message as if we had called it. | 1454 // NoSuchMethodError message as if we had called it. |
| 1451 if (element.isInstanceMember | 1455 if (element.isInstanceMember && |
| 1452 && !element.isGenerativeConstructorBody | 1456 !element.isGenerativeConstructorBody && |
| 1453 && (selector.mask == null || selector.mask.isNullable)) { | 1457 (mask == null || mask.isNullable)) { |
| 1454 addWithPosition( | 1458 addWithPosition( |
| 1455 new HFieldGet(null, providedArguments[0], backend.dynamicType, | 1459 new HFieldGet(null, providedArguments[0], backend.dynamicType, |
| 1456 isAssignable: false), | 1460 isAssignable: false), |
| 1457 currentNode); | 1461 currentNode); |
| 1458 } | 1462 } |
| 1459 List<HInstruction> compiledArguments = completeSendArgumentsList( | 1463 List<HInstruction> compiledArguments = completeSendArgumentsList( |
| 1460 function, selector, providedArguments, currentNode); | 1464 function, selector, providedArguments, currentNode); |
| 1461 enterInlinedMethod( | 1465 enterInlinedMethod( |
| 1462 function, currentNode, compiledArguments, instanceType: instanceType); | 1466 function, currentNode, compiledArguments, instanceType: instanceType); |
| 1463 inlinedFrom(function, () { | 1467 inlinedFrom(function, () { |
| (...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2290 // parameters of the generative constructor body. | 2294 // parameters of the generative constructor body. |
| 2291 currentClass.typeVariables.forEach((TypeVariableType argument) { | 2295 currentClass.typeVariables.forEach((TypeVariableType argument) { |
| 2292 // TODO(johnniwinther): Substitute [argument] with | 2296 // TODO(johnniwinther): Substitute [argument] with |
| 2293 // `localsHandler.substInContext(argument)`. | 2297 // `localsHandler.substInContext(argument)`. |
| 2294 bodyCallInputs.add(localsHandler.readLocal( | 2298 bodyCallInputs.add(localsHandler.readLocal( |
| 2295 localsHandler.getTypeVariableAsLocal(argument))); | 2299 localsHandler.getTypeVariableAsLocal(argument))); |
| 2296 }); | 2300 }); |
| 2297 } | 2301 } |
| 2298 | 2302 |
| 2299 if (!isNativeUpgradeFactory && // TODO(13836): Fix inlining. | 2303 if (!isNativeUpgradeFactory && // TODO(13836): Fix inlining. |
| 2300 tryInlineMethod(body, null, bodyCallInputs, function)) { | 2304 tryInlineMethod(body, null, null, bodyCallInputs, function)) { |
| 2301 pop(); | 2305 pop(); |
| 2302 } else { | 2306 } else { |
| 2303 HInvokeConstructorBody invoke = new HInvokeConstructorBody( | 2307 HInvokeConstructorBody invoke = new HInvokeConstructorBody( |
| 2304 body.declaration, bodyCallInputs, backend.nonNullType); | 2308 body.declaration, bodyCallInputs, backend.nonNullType); |
| 2305 invoke.sideEffects = | 2309 invoke.sideEffects = |
| 2306 compiler.world.getSideEffectsOfElement(constructor); | 2310 compiler.world.getSideEffectsOfElement(constructor); |
| 2307 add(invoke); | 2311 add(invoke); |
| 2308 } | 2312 } |
| 2309 } | 2313 } |
| 2310 if (inliningStack.isEmpty) { | 2314 if (inliningStack.isEmpty) { |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2443 return new HTypeConversion.withTypeRepresentation(type, kind, subtype, | 2447 return new HTypeConversion.withTypeRepresentation(type, kind, subtype, |
| 2444 original, typeVariable); | 2448 original, typeVariable); |
| 2445 } else if (type.isFunctionType) { | 2449 } else if (type.isFunctionType) { |
| 2446 String name = kind == HTypeConversion.CAST_TYPE_CHECK | 2450 String name = kind == HTypeConversion.CAST_TYPE_CHECK |
| 2447 ? '_asCheck' : '_assertCheck'; | 2451 ? '_asCheck' : '_assertCheck'; |
| 2448 | 2452 |
| 2449 List arguments = [buildFunctionType(type), original]; | 2453 List arguments = [buildFunctionType(type), original]; |
| 2450 pushInvokeDynamic( | 2454 pushInvokeDynamic( |
| 2451 null, | 2455 null, |
| 2452 new Selector.call(name, backend.jsHelperLibrary, 1), | 2456 new Selector.call(name, backend.jsHelperLibrary, 1), |
| 2457 null, | |
| 2453 arguments); | 2458 arguments); |
| 2454 | 2459 |
| 2455 return new HTypeConversion(type, kind, original.instructionType, pop()); | 2460 return new HTypeConversion(type, kind, original.instructionType, pop()); |
| 2456 } else { | 2461 } else { |
| 2457 return original.convertType(compiler, type, kind); | 2462 return original.convertType(compiler, type, kind); |
| 2458 } | 2463 } |
| 2459 } | 2464 } |
| 2460 | 2465 |
| 2461 HInstruction _trustType(HInstruction original, DartType type) { | 2466 HInstruction _trustType(HInstruction original, DartType type) { |
| 2462 assert(compiler.trustTypeAnnotations); | 2467 assert(compiler.trustTypeAnnotations); |
| (...skipping 722 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3185 if (operand is HConstant) { | 3190 if (operand is HConstant) { |
| 3186 UnaryOperation operation = constantSystem.lookupUnary(operator); | 3191 UnaryOperation operation = constantSystem.lookupUnary(operator); |
| 3187 HConstant constant = operand; | 3192 HConstant constant = operand; |
| 3188 ConstantValue folded = operation.fold(constant.constant); | 3193 ConstantValue folded = operation.fold(constant.constant); |
| 3189 if (folded != null) { | 3194 if (folded != null) { |
| 3190 stack.add(graph.addConstant(folded, compiler)); | 3195 stack.add(graph.addConstant(folded, compiler)); |
| 3191 return; | 3196 return; |
| 3192 } | 3197 } |
| 3193 } | 3198 } |
| 3194 | 3199 |
| 3195 pushInvokeDynamic(node, elements.getSelector(node), [operand]); | 3200 pushInvokeDynamic( |
| 3201 node, | |
| 3202 elements.getSelector(node), | |
| 3203 elements.getTypeMask(node), | |
| 3204 [operand]); | |
| 3196 } | 3205 } |
| 3197 | 3206 |
| 3198 @override | 3207 @override |
| 3199 void visitBinary(ast.Send node, | 3208 void visitBinary(ast.Send node, |
| 3200 ast.Node left, | 3209 ast.Node left, |
| 3201 BinaryOperator operator, | 3210 BinaryOperator operator, |
| 3202 ast.Node right, _) { | 3211 ast.Node right, _) { |
| 3203 handleBinary(node, left, right); | 3212 handleBinary(node, left, right); |
| 3204 } | 3213 } |
| 3205 | 3214 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 3217 void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) { | 3226 void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) { |
| 3218 handleBinary(node, left, right); | 3227 handleBinary(node, left, right); |
| 3219 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); | 3228 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); |
| 3220 } | 3229 } |
| 3221 | 3230 |
| 3222 void handleBinary(ast.Send node, ast.Node left, ast.Node right) { | 3231 void handleBinary(ast.Send node, ast.Node left, ast.Node right) { |
| 3223 visitBinarySend( | 3232 visitBinarySend( |
| 3224 visitAndPop(left), | 3233 visitAndPop(left), |
| 3225 visitAndPop(right), | 3234 visitAndPop(right), |
| 3226 elements.getSelector(node), | 3235 elements.getSelector(node), |
| 3236 elements.getTypeMask(node), | |
| 3227 node, | 3237 node, |
| 3228 location: node.selector); | 3238 location: node.selector); |
| 3229 } | 3239 } |
| 3230 | 3240 |
| 3231 /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and | 3241 /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and |
| 3232 /// remove use of [location] for source information. | 3242 /// remove use of [location] for source information. |
| 3233 void visitBinarySend(HInstruction left, | 3243 void visitBinarySend(HInstruction left, |
| 3234 HInstruction right, | 3244 HInstruction right, |
| 3235 Selector selector, | 3245 Selector selector, |
| 3246 TypeMask mask, | |
| 3236 ast.Send send, | 3247 ast.Send send, |
| 3237 {ast.Node location}) { | 3248 {ast.Node location}) { |
| 3238 pushInvokeDynamic(send, selector, [left, right], location: location); | 3249 pushInvokeDynamic(send, selector, mask, [left, right], location: location); |
| 3239 } | 3250 } |
| 3240 | 3251 |
| 3241 HInstruction generateInstanceSendReceiver(ast.Send send) { | 3252 HInstruction generateInstanceSendReceiver(ast.Send send) { |
| 3242 assert(Elements.isInstanceSend(send, elements)); | 3253 assert(Elements.isInstanceSend(send, elements)); |
| 3243 if (send.receiver == null) { | 3254 if (send.receiver == null) { |
| 3244 return localsHandler.readThis(); | 3255 return localsHandler.readThis(); |
| 3245 } | 3256 } |
| 3246 visit(send.receiver); | 3257 visit(send.receiver); |
| 3247 return pop(); | 3258 return pop(); |
| 3248 } | 3259 } |
| 3249 | 3260 |
| 3250 String noSuchMethodTargetSymbolString(Element error, [String prefix]) { | 3261 String noSuchMethodTargetSymbolString(Element error, [String prefix]) { |
| 3251 String result = error.name; | 3262 String result = error.name; |
| 3252 if (prefix == "set") return "$result="; | 3263 if (prefix == "set") return "$result="; |
| 3253 return result; | 3264 return result; |
| 3254 } | 3265 } |
| 3255 | 3266 |
| 3256 /** | 3267 /** |
| 3257 * Returns a set of interceptor classes that contain the given | 3268 * Returns a set of interceptor classes that contain the given |
| 3258 * [selector]. | 3269 * [selector]. |
| 3259 */ | 3270 */ |
| 3260 void generateInstanceGetterWithCompiledReceiver(ast.Send send, | 3271 void generateInstanceGetterWithCompiledReceiver( |
| 3261 Selector selector, | 3272 ast.Send send, |
| 3262 HInstruction receiver) { | 3273 Selector selector, |
| 3274 TypeMask mask, | |
| 3275 HInstruction receiver) { | |
| 3263 assert(Elements.isInstanceSend(send, elements)); | 3276 assert(Elements.isInstanceSend(send, elements)); |
| 3264 assert(selector.isGetter); | 3277 assert(selector.isGetter); |
| 3265 pushInvokeDynamic(send, selector, [receiver]); | 3278 pushInvokeDynamic(send, selector, mask, [receiver]); |
| 3266 } | 3279 } |
| 3267 | 3280 |
| 3268 /// Inserts a call to checkDeferredIsLoaded for [prefixElement]. | 3281 /// Inserts a call to checkDeferredIsLoaded for [prefixElement]. |
| 3269 /// If [prefixElement] is [null] ndo nothing. | 3282 /// If [prefixElement] is [null] ndo nothing. |
| 3270 void generateIsDeferredLoadedCheckIfNeeded(PrefixElement prefixElement, | 3283 void generateIsDeferredLoadedCheckIfNeeded(PrefixElement prefixElement, |
| 3271 ast.Node location) { | 3284 ast.Node location) { |
| 3272 if (prefixElement == null) return; | 3285 if (prefixElement == null) return; |
| 3273 String loadId = | 3286 String loadId = |
| 3274 compiler.deferredLoadTask.importDeferName[prefixElement.deferredImport]; | 3287 compiler.deferredLoadTask.importDeferName[prefixElement.deferredImport]; |
| 3275 HInstruction loadIdConstant = addConstantString(loadId); | 3288 HInstruction loadIdConstant = addConstantString(loadId); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3373 } else { | 3386 } else { |
| 3374 generateIsDeferredLoadedCheckOfSend(node); | 3387 generateIsDeferredLoadedCheckOfSend(node); |
| 3375 pushInvokeStatic(node, getter, <HInstruction>[]); | 3388 pushInvokeStatic(node, getter, <HInstruction>[]); |
| 3376 } | 3389 } |
| 3377 } | 3390 } |
| 3378 | 3391 |
| 3379 /// Generate a dynamic getter invocation. | 3392 /// Generate a dynamic getter invocation. |
| 3380 void generateDynamicGet(ast.Send node) { | 3393 void generateDynamicGet(ast.Send node) { |
| 3381 HInstruction receiver = generateInstanceSendReceiver(node); | 3394 HInstruction receiver = generateInstanceSendReceiver(node); |
| 3382 generateInstanceGetterWithCompiledReceiver( | 3395 generateInstanceGetterWithCompiledReceiver( |
| 3383 node, elements.getSelector(node), receiver); | 3396 node, elements.getSelector(node), elements.getTypeMask(node), receiver); |
| 3384 } | 3397 } |
| 3385 | 3398 |
| 3386 /// Generate a closurization of the static or top level [function]. | 3399 /// Generate a closurization of the static or top level [function]. |
| 3387 void generateStaticFunctionGet(ast.Send node, MethodElement function) { | 3400 void generateStaticFunctionGet(ast.Send node, MethodElement function) { |
| 3388 generateIsDeferredLoadedCheckOfSend(node); | 3401 generateIsDeferredLoadedCheckOfSend(node); |
| 3389 // TODO(5346): Try to avoid the need for calling [declaration] before | 3402 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 3390 // creating an [HStatic]. | 3403 // creating an [HStatic]. |
| 3391 push(new HStatic(function.declaration, backend.nonNullType)); | 3404 push(new HStatic(function.declaration, backend.nonNullType)); |
| 3392 // TODO(ahe): This should be registered in codegen. | 3405 // TODO(ahe): This should be registered in codegen. |
| 3393 registry.registerGetOfStaticFunction(function.declaration); | 3406 registry.registerGetOfStaticFunction(function.declaration); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 3420 // we will be able to later compress it as: | 3433 // we will be able to later compress it as: |
| 3421 // t1 || t1.x | 3434 // t1 || t1.x |
| 3422 HInstruction expression; | 3435 HInstruction expression; |
| 3423 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 3436 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 3424 brancher.handleConditional( | 3437 brancher.handleConditional( |
| 3425 () { | 3438 () { |
| 3426 expression = visitAndPop(receiver); | 3439 expression = visitAndPop(receiver); |
| 3427 pushCheckNull(expression); | 3440 pushCheckNull(expression); |
| 3428 }, | 3441 }, |
| 3429 () => stack.add(expression), | 3442 () => stack.add(expression), |
| 3430 () => generateInstanceGetterWithCompiledReceiver( | 3443 () { |
| 3431 node, elements.getSelector(node), expression)); | 3444 generateInstanceGetterWithCompiledReceiver( |
| 3445 node, | |
| 3446 elements.getSelector(node), | |
| 3447 elements.getTypeMask(node), | |
| 3448 expression); | |
| 3449 }); | |
| 3432 } | 3450 } |
| 3433 | 3451 |
| 3434 /// Pushes a boolean checking [expression] against null. | 3452 /// Pushes a boolean checking [expression] against null. |
| 3435 pushCheckNull(HInstruction expression) { | 3453 pushCheckNull(HInstruction expression) { |
| 3436 push(new HIdentity(expression, graph.addConstantNull(compiler), | 3454 push(new HIdentity(expression, graph.addConstantNull(compiler), |
| 3437 null, backend.boolType)); | 3455 null, backend.boolType)); |
| 3438 } | 3456 } |
| 3439 | 3457 |
| 3440 @override | 3458 @override |
| 3441 void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) { | 3459 void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3505 ast.Send node, | 3523 ast.Send node, |
| 3506 FunctionElement getter, | 3524 FunctionElement getter, |
| 3507 _) { | 3525 _) { |
| 3508 generateStaticGetterGet(node, getter); | 3526 generateStaticGetterGet(node, getter); |
| 3509 } | 3527 } |
| 3510 | 3528 |
| 3511 void generatePossiblyConditionalInstanceSetter(ast.Send send, | 3529 void generatePossiblyConditionalInstanceSetter(ast.Send send, |
| 3512 HInstruction pushReceiver(), | 3530 HInstruction pushReceiver(), |
| 3513 HInstruction pushValue(), | 3531 HInstruction pushValue(), |
| 3514 {Selector selector, | 3532 {Selector selector, |
| 3533 TypeMask mask, | |
| 3515 ast.Node location}) { | 3534 ast.Node location}) { |
| 3516 if (send.isConditional) { | 3535 if (send.isConditional) { |
| 3517 SsaBranchBuilder brancher = new SsaBranchBuilder(this, send); | 3536 SsaBranchBuilder brancher = new SsaBranchBuilder(this, send); |
| 3518 // compile e?.x = e2 to: | 3537 // compile e?.x = e2 to: |
| 3519 // | 3538 // |
| 3520 // t1 = e | 3539 // t1 = e |
| 3521 // if (t1 == null) | 3540 // if (t1 == null) |
| 3522 // result = t1 // same as result = null | 3541 // result = t1 // same as result = null |
| 3523 // else | 3542 // else |
| 3524 // result = e.x = e2 | 3543 // result = e.x = e2 |
| 3525 HInstruction receiver; | 3544 HInstruction receiver; |
| 3526 brancher.handleConditional( | 3545 brancher.handleConditional( |
| 3527 () { | 3546 () { |
| 3528 receiver = pushReceiver(); | 3547 receiver = pushReceiver(); |
| 3529 pushCheckNull(receiver); | 3548 pushCheckNull(receiver); |
| 3530 }, | 3549 }, |
| 3531 () => stack.add(receiver), | 3550 () => stack.add(receiver), |
| 3532 () => generateInstanceSetterWithCompiledReceiver( | 3551 () => generateInstanceSetterWithCompiledReceiver( |
| 3533 send, receiver, pushValue(), | 3552 send, receiver, pushValue(), |
| 3534 selector: selector, location: location)); | 3553 selector: selector, mask: mask, location: location)); |
| 3535 } else { | 3554 } else { |
| 3536 generateInstanceSetterWithCompiledReceiver( | 3555 generateInstanceSetterWithCompiledReceiver( |
| 3537 send, pushReceiver(), pushValue(), | 3556 send, pushReceiver(), pushValue(), |
| 3538 selector: selector, location: location); | 3557 selector: selector, mask: mask, location: location); |
| 3539 } | 3558 } |
| 3540 } | 3559 } |
| 3541 | 3560 |
| 3542 void generateInstanceSetterWithCompiledReceiver(ast.Send send, | 3561 void generateInstanceSetterWithCompiledReceiver(ast.Send send, |
| 3543 HInstruction receiver, | 3562 HInstruction receiver, |
| 3544 HInstruction value, | 3563 HInstruction value, |
| 3545 {Selector selector, | 3564 {Selector selector, |
| 3565 TypeMask mask, | |
| 3546 ast.Node location}) { | 3566 ast.Node location}) { |
| 3547 assert(send == null || Elements.isInstanceSend(send, elements)); | 3567 assert(send == null || Elements.isInstanceSend(send, elements)); |
| 3548 if (selector == null) { | 3568 if (selector == null) { |
| 3549 assert(send != null); | 3569 assert(send != null); |
| 3550 selector = elements.getSelector(send); | 3570 selector = elements.getSelector(send); |
| 3571 if (mask == null) { | |
| 3572 mask = elements.getTypeMask(send); | |
| 3573 } | |
| 3551 } | 3574 } |
| 3552 if (location == null) { | 3575 if (location == null) { |
| 3553 assert(send != null); | 3576 assert(send != null); |
| 3554 location = send; | 3577 location = send; |
| 3555 } | 3578 } |
| 3556 assert(selector.isSetter); | 3579 assert(selector.isSetter); |
| 3557 pushInvokeDynamic(location, selector, [receiver, value]); | 3580 pushInvokeDynamic(location, selector, mask, [receiver, value]); |
| 3558 pop(); | 3581 pop(); |
| 3559 stack.add(value); | 3582 stack.add(value); |
| 3560 } | 3583 } |
| 3561 | 3584 |
| 3562 void generateNonInstanceSetter(ast.SendSet send, | 3585 void generateNonInstanceSetter(ast.SendSet send, |
| 3563 Element element, | 3586 Element element, |
| 3564 HInstruction value, | 3587 HInstruction value, |
| 3565 {ast.Node location}) { | 3588 {ast.Node location}) { |
| 3566 assert(send == null || !Elements.isInstanceSend(send, elements)); | 3589 assert(send == null || !Elements.isInstanceSend(send, elements)); |
| 3567 if (location == null) { | 3590 if (location == null) { |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3682 push(new HNot(instruction, backend.boolType)); | 3705 push(new HNot(instruction, backend.boolType)); |
| 3683 } | 3706 } |
| 3684 | 3707 |
| 3685 HInstruction buildIsNode(ast.Node node, | 3708 HInstruction buildIsNode(ast.Node node, |
| 3686 DartType type, | 3709 DartType type, |
| 3687 HInstruction expression) { | 3710 HInstruction expression) { |
| 3688 type = localsHandler.substInContext(type).unalias(compiler); | 3711 type = localsHandler.substInContext(type).unalias(compiler); |
| 3689 if (type.isFunctionType) { | 3712 if (type.isFunctionType) { |
| 3690 List arguments = [buildFunctionType(type), expression]; | 3713 List arguments = [buildFunctionType(type), expression]; |
| 3691 pushInvokeDynamic( | 3714 pushInvokeDynamic( |
| 3692 node, new Selector.call('_isTest', backend.jsHelperLibrary, 1), | 3715 node, |
| 3716 new Selector.call('_isTest', backend.jsHelperLibrary, 1), | |
| 3717 null, | |
| 3693 arguments); | 3718 arguments); |
| 3694 return new HIs.compound(type, expression, pop(), backend.boolType); | 3719 return new HIs.compound(type, expression, pop(), backend.boolType); |
| 3695 } else if (type.isTypeVariable) { | 3720 } else if (type.isTypeVariable) { |
| 3696 HInstruction runtimeType = addTypeVariableReference(type); | 3721 HInstruction runtimeType = addTypeVariableReference(type); |
| 3697 Element helper = backend.getCheckSubtypeOfRuntimeType(); | 3722 Element helper = backend.getCheckSubtypeOfRuntimeType(); |
| 3698 List<HInstruction> inputs = <HInstruction>[expression, runtimeType]; | 3723 List<HInstruction> inputs = <HInstruction>[expression, runtimeType]; |
| 3699 pushInvokeStatic(null, helper, inputs, typeMask: backend.boolType); | 3724 pushInvokeStatic(null, helper, inputs, typeMask: backend.boolType); |
| 3700 HInstruction call = pop(); | 3725 HInstruction call = pop(); |
| 3701 return new HIs.variable(type, expression, call, backend.boolType); | 3726 return new HIs.variable(type, expression, call, backend.boolType); |
| 3702 } else if (RuntimeTypes.hasTypeArguments(type)) { | 3727 } else if (RuntimeTypes.hasTypeArguments(type)) { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3804 } | 3829 } |
| 3805 | 3830 |
| 3806 /// Generate a dynamic method, getter or setter invocation. | 3831 /// Generate a dynamic method, getter or setter invocation. |
| 3807 void generateDynamicSend(ast.Send node) { | 3832 void generateDynamicSend(ast.Send node) { |
| 3808 HInstruction receiver = generateInstanceSendReceiver(node); | 3833 HInstruction receiver = generateInstanceSendReceiver(node); |
| 3809 _generateDynamicSend(node, receiver); | 3834 _generateDynamicSend(node, receiver); |
| 3810 } | 3835 } |
| 3811 | 3836 |
| 3812 void _generateDynamicSend(ast.Send node, HInstruction receiver) { | 3837 void _generateDynamicSend(ast.Send node, HInstruction receiver) { |
| 3813 Selector selector = elements.getSelector(node); | 3838 Selector selector = elements.getSelector(node); |
| 3839 TypeMask mask = elements.getTypeMask(node); | |
| 3814 | 3840 |
| 3815 List<HInstruction> inputs = <HInstruction>[]; | 3841 List<HInstruction> inputs = <HInstruction>[]; |
| 3816 inputs.add(receiver); | 3842 inputs.add(receiver); |
| 3817 addDynamicSendArgumentsToList(node, inputs); | 3843 addDynamicSendArgumentsToList(node, inputs); |
| 3818 | 3844 |
| 3819 pushInvokeDynamic(node, selector, inputs); | 3845 pushInvokeDynamic(node, selector, mask, inputs); |
| 3820 if (selector.isSetter || selector.isIndexSet) { | 3846 if (selector.isSetter || selector.isIndexSet) { |
| 3821 pop(); | 3847 pop(); |
| 3822 stack.add(inputs.last); | 3848 stack.add(inputs.last); |
| 3823 } | 3849 } |
| 3824 } | 3850 } |
| 3825 | 3851 |
| 3826 @override | 3852 @override |
| 3827 visitDynamicPropertyInvoke( | 3853 visitDynamicPropertyInvoke( |
| 3828 ast.Send node, | 3854 ast.Send node, |
| 3829 ast.Node receiver, | 3855 ast.Node receiver, |
| (...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4173 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); | 4199 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); |
| 4174 stack.add(graph.addConstantNull(compiler)); | 4200 stack.add(graph.addConstantNull(compiler)); |
| 4175 } | 4201 } |
| 4176 | 4202 |
| 4177 void handleForeignJsCallInIsolate(ast.Send node) { | 4203 void handleForeignJsCallInIsolate(ast.Send node) { |
| 4178 Link<ast.Node> link = node.arguments; | 4204 Link<ast.Node> link = node.arguments; |
| 4179 if (!compiler.hasIsolateSupport) { | 4205 if (!compiler.hasIsolateSupport) { |
| 4180 // If the isolate library is not used, we just invoke the | 4206 // If the isolate library is not used, we just invoke the |
| 4181 // closure. | 4207 // closure. |
| 4182 visit(link.tail.head); | 4208 visit(link.tail.head); |
| 4183 Selector selector = new Selector.callClosure(0); | 4209 push(new HInvokeClosure(new Selector.callClosure(0), |
| 4184 push(new HInvokeClosure(selector, | |
| 4185 <HInstruction>[pop()], | 4210 <HInstruction>[pop()], |
| 4186 backend.dynamicType)); | 4211 backend.dynamicType)); |
| 4187 } else { | 4212 } else { |
| 4188 // Call a helper method from the isolate library. | 4213 // Call a helper method from the isolate library. |
| 4189 Element element = backend.isolateHelperLibrary.find('_callInIsolate'); | 4214 Element element = backend.isolateHelperLibrary.find('_callInIsolate'); |
| 4190 if (element == null) { | 4215 if (element == null) { |
| 4191 compiler.internalError(node, | 4216 compiler.internalError(node, |
| 4192 'Isolate library and compiler mismatch.'); | 4217 'Isolate library and compiler mismatch.'); |
| 4193 } | 4218 } |
| 4194 List<HInstruction> inputs = <HInstruction>[]; | 4219 List<HInstruction> inputs = <HInstruction>[]; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4316 String name = selector.name; | 4341 String name = selector.name; |
| 4317 | 4342 |
| 4318 ClassElement cls = currentNonClosureClass; | 4343 ClassElement cls = currentNonClosureClass; |
| 4319 Element element = cls.lookupSuperMember(Compiler.NO_SUCH_METHOD); | 4344 Element element = cls.lookupSuperMember(Compiler.NO_SUCH_METHOD); |
| 4320 if (compiler.enabledInvokeOn | 4345 if (compiler.enabledInvokeOn |
| 4321 && element.enclosingElement.declaration != compiler.objectClass) { | 4346 && element.enclosingElement.declaration != compiler.objectClass) { |
| 4322 // Register the call as dynamic if [noSuchMethod] on the super | 4347 // Register the call as dynamic if [noSuchMethod] on the super |
| 4323 // class is _not_ the default implementation from [Object], in | 4348 // class is _not_ the default implementation from [Object], in |
| 4324 // case the [noSuchMethod] implementation calls | 4349 // case the [noSuchMethod] implementation calls |
| 4325 // [JSInvocationMirror._invokeOn]. | 4350 // [JSInvocationMirror._invokeOn]. |
| 4326 registry.registerSelectorUse(selector.asUntyped); | 4351 registry.registerSelectorUse(selector); |
| 4327 } | 4352 } |
| 4328 String publicName = name; | 4353 String publicName = name; |
| 4329 if (selector.isSetter) publicName += '='; | 4354 if (selector.isSetter) publicName += '='; |
| 4330 | 4355 |
| 4331 ConstantValue nameConstant = constantSystem.createString( | 4356 ConstantValue nameConstant = constantSystem.createString( |
| 4332 new ast.DartString.literal(publicName)); | 4357 new ast.DartString.literal(publicName)); |
| 4333 | 4358 |
| 4334 String internalName = backend.namer.invocationName(selector); | 4359 String internalName = backend.namer.invocationName(selector); |
| 4335 ConstantValue internalNameConstant = | 4360 ConstantValue internalNameConstant = |
| 4336 constantSystem.createString(new ast.DartString.literal(internalName)); | 4361 constantSystem.createString(new ast.DartString.literal(internalName)); |
| (...skipping 995 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5332 // in if it is not used (e.g., in a try/catch). | 5357 // in if it is not used (e.g., in a try/catch). |
| 5333 HInstruction target = pop(); | 5358 HInstruction target = pop(); |
| 5334 generateCallInvoke(node, target); | 5359 generateCallInvoke(node, target); |
| 5335 } | 5360 } |
| 5336 | 5361 |
| 5337 /// Generate a '.call' invocation on [target]. | 5362 /// Generate a '.call' invocation on [target]. |
| 5338 void generateCallInvoke(ast.Send node, HInstruction target) { | 5363 void generateCallInvoke(ast.Send node, HInstruction target) { |
| 5339 Selector selector = elements.getSelector(node); | 5364 Selector selector = elements.getSelector(node); |
| 5340 List<HInstruction> inputs = <HInstruction>[target]; | 5365 List<HInstruction> inputs = <HInstruction>[target]; |
| 5341 addDynamicSendArgumentsToList(node, inputs); | 5366 addDynamicSendArgumentsToList(node, inputs); |
| 5342 Selector closureSelector = new Selector.callClosureFrom(selector); | |
| 5343 pushWithPosition( | 5367 pushWithPosition( |
| 5344 new HInvokeClosure(closureSelector, inputs, backend.dynamicType), node); | 5368 new HInvokeClosure( |
| 5369 new Selector.callClosureFrom(selector), | |
| 5370 inputs, backend.dynamicType), | |
| 5371 node); | |
| 5345 } | 5372 } |
| 5346 | 5373 |
| 5347 visitGetterSend(ast.Send node) { | 5374 visitGetterSend(ast.Send node) { |
| 5348 internalError(node, "Unexpected visitGetterSend"); | 5375 internalError(node, "Unexpected visitGetterSend"); |
| 5349 } | 5376 } |
| 5350 | 5377 |
| 5351 // TODO(antonm): migrate rest of SsaFromAstMixin to internalError. | 5378 // TODO(antonm): migrate rest of SsaFromAstMixin to internalError. |
| 5352 internalError(Spannable node, String reason) { | 5379 internalError(Spannable node, String reason) { |
| 5353 compiler.internalError(node, reason); | 5380 compiler.internalError(node, reason); |
| 5354 } | 5381 } |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5463 String nameString = stringConstant.toDartString().slowToString(); | 5490 String nameString = stringConstant.toDartString().slowToString(); |
| 5464 registry.registerConstSymbol(nameString); | 5491 registry.registerConstSymbol(nameString); |
| 5465 } | 5492 } |
| 5466 } else { | 5493 } else { |
| 5467 handleNewSend(node); | 5494 handleNewSend(node); |
| 5468 } | 5495 } |
| 5469 } | 5496 } |
| 5470 | 5497 |
| 5471 void pushInvokeDynamic(ast.Node node, | 5498 void pushInvokeDynamic(ast.Node node, |
| 5472 Selector selector, | 5499 Selector selector, |
| 5500 TypeMask mask, | |
| 5473 List<HInstruction> arguments, | 5501 List<HInstruction> arguments, |
| 5474 {ast.Node location}) { | 5502 {ast.Node location}) { |
| 5475 if (location == null) location = node; | 5503 if (location == null) location = node; |
| 5476 | 5504 |
| 5477 // We prefer to not inline certain operations on indexables, | 5505 // We prefer to not inline certain operations on indexables, |
| 5478 // because the constant folder will handle them better and turn | 5506 // because the constant folder will handle them better and turn |
| 5479 // them into simpler instructions that allow further | 5507 // them into simpler instructions that allow further |
| 5480 // optimizations. | 5508 // optimizations. |
| 5481 bool isOptimizableOperationOnIndexable(Selector selector, Element element) { | 5509 bool isOptimizableOperationOnIndexable(Selector selector, Element element) { |
| 5482 bool isLength = selector.isGetter | 5510 bool isLength = selector.isGetter |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 5503 if (selector.isIndex) return true; | 5531 if (selector.isIndex) return true; |
| 5504 if (selector.isIndexSet) return true; | 5532 if (selector.isIndexSet) return true; |
| 5505 if (element == backend.jsArrayAdd | 5533 if (element == backend.jsArrayAdd |
| 5506 || element == backend.jsArrayRemoveLast | 5534 || element == backend.jsArrayRemoveLast |
| 5507 || element == backend.jsStringSplit) { | 5535 || element == backend.jsStringSplit) { |
| 5508 return true; | 5536 return true; |
| 5509 } | 5537 } |
| 5510 return false; | 5538 return false; |
| 5511 } | 5539 } |
| 5512 | 5540 |
| 5513 Element element = compiler.world.locateSingleElement(selector); | 5541 Element element = compiler.world.locateSingleElement(selector, mask); |
| 5514 if (element != null | 5542 if (element != null && |
| 5515 && !element.isField | 5543 !element.isField && |
| 5516 && !(element.isGetter && selector.isCall) | 5544 !(element.isGetter && selector.isCall) && |
| 5517 && !(element.isFunction && selector.isGetter) | 5545 !(element.isFunction && selector.isGetter) && |
| 5518 && !isOptimizableOperation(selector, element)) { | 5546 !isOptimizableOperation(selector, element)) { |
| 5519 if (tryInlineMethod(element, selector, arguments, node)) { | 5547 if (selector.name == 'double') { |
| 5548 //debugPrint('Try to inline $node call to $element'); | |
| 5549 } | |
| 5550 if (tryInlineMethod(element, selector, mask, arguments, node)) { | |
| 5520 return; | 5551 return; |
| 5521 } | 5552 } |
| 5553 if (selector.name == 'double') { | |
|
karlklose
2015/06/17 12:43:11
Remove debug code.
Johnni Winther
2015/06/17 13:03:52
Done.
| |
| 5554 //debugPrint('Failed to inline $node'); | |
| 5555 } | |
| 5522 } | 5556 } |
| 5523 | 5557 |
| 5524 HInstruction receiver = arguments[0]; | 5558 HInstruction receiver = arguments[0]; |
| 5525 List<HInstruction> inputs = <HInstruction>[]; | 5559 List<HInstruction> inputs = <HInstruction>[]; |
| 5526 bool isIntercepted = backend.isInterceptedSelector(selector); | 5560 bool isIntercepted = backend.isInterceptedSelector(selector); |
| 5527 if (isIntercepted) { | 5561 if (isIntercepted) { |
| 5528 inputs.add(invokeInterceptor(receiver)); | 5562 inputs.add(invokeInterceptor(receiver)); |
| 5529 } | 5563 } |
| 5530 inputs.addAll(arguments); | 5564 inputs.addAll(arguments); |
| 5531 TypeMask type = TypeMaskFactory.inferredTypeForSelector(selector, compiler); | 5565 TypeMask type = |
| 5566 TypeMaskFactory.inferredTypeForSelector(selector, mask, compiler); | |
| 5532 if (selector.isGetter) { | 5567 if (selector.isGetter) { |
| 5533 pushWithPosition( | 5568 pushWithPosition( |
| 5534 new HInvokeDynamicGetter(selector, null, inputs, type), | 5569 new HInvokeDynamicGetter(selector, mask, null, inputs, type), |
| 5535 location); | 5570 location); |
| 5536 } else if (selector.isSetter) { | 5571 } else if (selector.isSetter) { |
| 5537 pushWithPosition( | 5572 pushWithPosition( |
| 5538 new HInvokeDynamicSetter(selector, null, inputs, type), | 5573 new HInvokeDynamicSetter(selector, mask, null, inputs, type), |
| 5539 location); | 5574 location); |
| 5540 } else { | 5575 } else { |
| 5541 pushWithPosition( | 5576 pushWithPosition( |
| 5542 new HInvokeDynamicMethod(selector, inputs, type, isIntercepted), | 5577 new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted), |
| 5543 location); | 5578 location); |
| 5544 } | 5579 } |
| 5545 } | 5580 } |
| 5546 | 5581 |
| 5547 void pushInvokeStatic(ast.Node location, | 5582 void pushInvokeStatic(ast.Node location, |
| 5548 Element element, | 5583 Element element, |
| 5549 List<HInstruction> arguments, | 5584 List<HInstruction> arguments, |
| 5550 {TypeMask typeMask, | 5585 {TypeMask typeMask, |
| 5551 InterfaceType instanceType}) { | 5586 InterfaceType instanceType}) { |
| 5552 if (tryInlineMethod(element, null, arguments, location, | 5587 if (tryInlineMethod(element, null, null, arguments, location, |
| 5553 instanceType: instanceType)) { | 5588 instanceType: instanceType)) { |
| 5554 return; | 5589 return; |
| 5555 } | 5590 } |
| 5556 | 5591 |
| 5557 if (typeMask == null) { | 5592 if (typeMask == null) { |
| 5558 typeMask = | 5593 typeMask = |
| 5559 TypeMaskFactory.inferredReturnTypeForElement(element, compiler); | 5594 TypeMaskFactory.inferredReturnTypeForElement(element, compiler); |
| 5560 } | 5595 } |
| 5561 bool targetCanThrow = !compiler.world.getCannotThrow(element); | 5596 bool targetCanThrow = !compiler.world.getCannotThrow(element); |
| 5562 // TODO(5346): Try to avoid the need for calling [declaration] before | 5597 // TODO(5346): Try to avoid the need for calling [declaration] before |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5597 } else { | 5632 } else { |
| 5598 type = TypeMaskFactory.inferredReturnTypeForElement(element, compiler); | 5633 type = TypeMaskFactory.inferredReturnTypeForElement(element, compiler); |
| 5599 } | 5634 } |
| 5600 HInstruction instruction = new HInvokeSuper( | 5635 HInstruction instruction = new HInvokeSuper( |
| 5601 element, | 5636 element, |
| 5602 currentNonClosureClass, | 5637 currentNonClosureClass, |
| 5603 selector, | 5638 selector, |
| 5604 inputs, | 5639 inputs, |
| 5605 type, | 5640 type, |
| 5606 isSetter: selector.isSetter || selector.isIndexSet); | 5641 isSetter: selector.isSetter || selector.isIndexSet); |
| 5607 instruction.sideEffects = compiler.world.getSideEffectsOfSelector(selector); | 5642 instruction.sideEffects = |
| 5643 compiler.world.getSideEffectsOfSelector(selector, null); | |
| 5608 return instruction; | 5644 return instruction; |
| 5609 } | 5645 } |
| 5610 | 5646 |
| 5611 void handleComplexOperatorSend(ast.SendSet node, | 5647 void handleComplexOperatorSend(ast.SendSet node, |
| 5612 HInstruction receiver, | 5648 HInstruction receiver, |
| 5613 Link<ast.Node> arguments) { | 5649 Link<ast.Node> arguments) { |
| 5614 HInstruction rhs; | 5650 HInstruction rhs; |
| 5615 if (node.isPrefix || node.isPostfix) { | 5651 if (node.isPrefix || node.isPostfix) { |
| 5616 rhs = graph.addConstantInt(1, compiler); | 5652 rhs = graph.addConstantInt(1, compiler); |
| 5617 } else { | 5653 } else { |
| 5618 visit(arguments.head); | 5654 visit(arguments.head); |
| 5619 assert(arguments.tail.isEmpty); | 5655 assert(arguments.tail.isEmpty); |
| 5620 rhs = pop(); | 5656 rhs = pop(); |
| 5621 } | 5657 } |
| 5622 visitBinarySend(receiver, rhs, | 5658 visitBinarySend(receiver, rhs, |
| 5623 elements.getOperatorSelectorInComplexSendSet(node), | 5659 elements.getOperatorSelectorInComplexSendSet(node), |
| 5660 elements.getOperatorTypeMaskInComplexSendSet(node), | |
| 5624 node, | 5661 node, |
| 5625 location: node.assignmentOperator); | 5662 location: node.assignmentOperator); |
| 5626 } | 5663 } |
| 5627 | 5664 |
| 5628 @override | 5665 @override |
| 5629 handleSendSet(ast.SendSet node) { | 5666 handleSendSet(ast.SendSet node) { |
| 5630 generateIsDeferredLoadedCheckOfSend(node); | 5667 generateIsDeferredLoadedCheckOfSend(node); |
| 5631 Element element = elements[node]; | 5668 Element element = elements[node]; |
| 5632 if (!Elements.isUnresolved(element) && element.impliesType) { | 5669 if (!Elements.isUnresolved(element) && element.impliesType) { |
| 5633 ast.Identifier selector = node.selector; | 5670 ast.Identifier selector = node.selector; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5708 HInstruction index; | 5745 HInstruction index; |
| 5709 if (node.isIndex) { | 5746 if (node.isIndex) { |
| 5710 visit(arguments.head); | 5747 visit(arguments.head); |
| 5711 arguments = arguments.tail; | 5748 arguments = arguments.tail; |
| 5712 index = pop(); | 5749 index = pop(); |
| 5713 } | 5750 } |
| 5714 | 5751 |
| 5715 pushInvokeDynamic( | 5752 pushInvokeDynamic( |
| 5716 node, | 5753 node, |
| 5717 elements.getGetterSelectorInComplexSendSet(node), | 5754 elements.getGetterSelectorInComplexSendSet(node), |
| 5755 elements.getGetterTypeMaskInComplexSendSet(node), | |
| 5718 [receiver, index]); | 5756 [receiver, index]); |
| 5719 HInstruction getterInstruction = pop(); | 5757 HInstruction getterInstruction = pop(); |
| 5720 if (node.isIfNullAssignment) { | 5758 if (node.isIfNullAssignment) { |
| 5721 // Compile x[i] ??= e as: | 5759 // Compile x[i] ??= e as: |
| 5722 // t1 = x[i] | 5760 // t1 = x[i] |
| 5723 // if (t1 == null) | 5761 // if (t1 == null) |
| 5724 // t1 = x[i] = e; | 5762 // t1 = x[i] = e; |
| 5725 // result = t1 | 5763 // result = t1 |
| 5726 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5764 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 5727 brancher.handleIfNull(() => stack.add(getterInstruction), | 5765 brancher.handleIfNull(() => stack.add(getterInstruction), |
| 5728 () { | 5766 () { |
| 5729 visit(arguments.head); | 5767 visit(arguments.head); |
| 5730 HInstruction value = pop(); | 5768 HInstruction value = pop(); |
| 5731 pushInvokeDynamic( | 5769 pushInvokeDynamic( |
| 5732 node, elements.getSelector(node), [receiver, index, value]); | 5770 node, |
| 5771 elements.getSelector(node), | |
| 5772 elements.getTypeMask(node), | |
| 5773 [receiver, index, value]); | |
| 5733 pop(); | 5774 pop(); |
| 5734 stack.add(value); | 5775 stack.add(value); |
| 5735 }); | 5776 }); |
| 5736 } else { | 5777 } else { |
| 5737 handleComplexOperatorSend(node, getterInstruction, arguments); | 5778 handleComplexOperatorSend(node, getterInstruction, arguments); |
| 5738 HInstruction value = pop(); | 5779 HInstruction value = pop(); |
| 5739 pushInvokeDynamic( | 5780 pushInvokeDynamic( |
| 5740 node, elements.getSelector(node), [receiver, index, value]); | 5781 node, |
| 5782 elements.getSelector(node), | |
| 5783 elements.getTypeMask(node), | |
| 5784 [receiver, index, value]); | |
| 5741 pop(); | 5785 pop(); |
| 5742 if (node.isPostfix) { | 5786 if (node.isPostfix) { |
| 5743 stack.add(getterInstruction); | 5787 stack.add(getterInstruction); |
| 5744 } else { | 5788 } else { |
| 5745 stack.add(value); | 5789 stack.add(value); |
| 5746 } | 5790 } |
| 5747 } | 5791 } |
| 5748 } | 5792 } |
| 5749 } else if ("=" == op.source) { | 5793 } else if ("=" == op.source) { |
| 5750 Link<ast.Node> link = node.arguments; | 5794 Link<ast.Node> link = node.arguments; |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 5774 generateThrowNoSuchMethod(node, selector.source, | 5818 generateThrowNoSuchMethod(node, selector.source, |
| 5775 argumentNodes: node.arguments); | 5819 argumentNodes: node.arguments); |
| 5776 } | 5820 } |
| 5777 return; | 5821 return; |
| 5778 } | 5822 } |
| 5779 | 5823 |
| 5780 if (Elements.isInstanceSend(node, elements)) { | 5824 if (Elements.isInstanceSend(node, elements)) { |
| 5781 void generateAssignment(HInstruction receiver) { | 5825 void generateAssignment(HInstruction receiver) { |
| 5782 // desugars `e.x op= e2` to `e.x = e.x op e2` | 5826 // desugars `e.x op= e2` to `e.x = e.x op e2` |
| 5783 generateInstanceGetterWithCompiledReceiver( | 5827 generateInstanceGetterWithCompiledReceiver( |
| 5784 node, elements.getGetterSelectorInComplexSendSet(node), receiver); | 5828 node, |
| 5829 elements.getGetterSelectorInComplexSendSet(node), | |
| 5830 elements.getGetterTypeMaskInComplexSendSet(node), | |
| 5831 receiver); | |
| 5785 HInstruction getterInstruction = pop(); | 5832 HInstruction getterInstruction = pop(); |
| 5786 if (node.isIfNullAssignment) { | 5833 if (node.isIfNullAssignment) { |
| 5787 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); | 5834 SsaBranchBuilder brancher = new SsaBranchBuilder(this, node); |
| 5788 brancher.handleIfNull(() => stack.add(getterInstruction), | 5835 brancher.handleIfNull(() => stack.add(getterInstruction), |
| 5789 () { | 5836 () { |
| 5790 visit(node.arguments.head); | 5837 visit(node.arguments.head); |
| 5791 generateInstanceSetterWithCompiledReceiver( | 5838 generateInstanceSetterWithCompiledReceiver( |
| 5792 node, receiver, pop()); | 5839 node, receiver, pop()); |
| 5793 }); | 5840 }); |
| 5794 } else { | 5841 } else { |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6202 HInstruction expression = pop(); | 6249 HInstruction expression = pop(); |
| 6203 pushInvokeStatic(node, | 6250 pushInvokeStatic(node, |
| 6204 backend.getStreamIteratorConstructor(), | 6251 backend.getStreamIteratorConstructor(), |
| 6205 [expression, graph.addConstantNull(compiler)]); | 6252 [expression, graph.addConstantNull(compiler)]); |
| 6206 streamIterator = pop(); | 6253 streamIterator = pop(); |
| 6207 | 6254 |
| 6208 void buildInitializer() {} | 6255 void buildInitializer() {} |
| 6209 | 6256 |
| 6210 HInstruction buildCondition() { | 6257 HInstruction buildCondition() { |
| 6211 Selector selector = elements.getMoveNextSelector(node); | 6258 Selector selector = elements.getMoveNextSelector(node); |
| 6212 pushInvokeDynamic(node, selector, [streamIterator]); | 6259 TypeMask mask = elements.getMoveNextTypeMask(node); |
| 6260 pushInvokeDynamic(node, selector, mask, [streamIterator]); | |
| 6213 HInstruction future = pop(); | 6261 HInstruction future = pop(); |
| 6214 push(new HAwait(future, new TypeMask.subclass(compiler.objectClass, | 6262 push(new HAwait(future, new TypeMask.subclass(compiler.objectClass, |
| 6215 compiler.world))); | 6263 compiler.world))); |
| 6216 return popBoolified(); | 6264 return popBoolified(); |
| 6217 } | 6265 } |
| 6218 void buildBody() { | 6266 void buildBody() { |
| 6219 Selector call = elements.getCurrentSelector(node); | 6267 Selector call = elements.getCurrentSelector(node); |
| 6220 pushInvokeDynamic(node, call, [streamIterator]); | 6268 TypeMask callMask = elements.getCurrentTypeMask(node); |
| 6269 pushInvokeDynamic(node, call, callMask, [streamIterator]); | |
| 6221 | 6270 |
| 6222 ast.Node identifier = node.declaredIdentifier; | 6271 ast.Node identifier = node.declaredIdentifier; |
| 6223 Element variable = elements.getForInVariable(node); | 6272 Element variable = elements.getForInVariable(node); |
| 6224 Selector selector = elements.getSelector(identifier); | 6273 Selector selector = elements.getSelector(identifier); |
| 6274 TypeMask mask = elements.getTypeMask(identifier); | |
| 6225 | 6275 |
| 6226 HInstruction value = pop(); | 6276 HInstruction value = pop(); |
| 6227 if (identifier.asSend() != null | 6277 if (identifier.asSend() != null |
| 6228 && Elements.isInstanceSend(identifier, elements)) { | 6278 && Elements.isInstanceSend(identifier, elements)) { |
| 6229 HInstruction receiver = generateInstanceSendReceiver(identifier); | 6279 HInstruction receiver = generateInstanceSendReceiver(identifier); |
| 6230 assert(receiver != null); | 6280 assert(receiver != null); |
| 6231 generateInstanceSetterWithCompiledReceiver( | 6281 generateInstanceSetterWithCompiledReceiver( |
| 6232 null, | 6282 null, |
| 6233 receiver, | 6283 receiver, |
| 6234 value, | 6284 value, |
| 6235 selector: selector, | 6285 selector: selector, |
| 6286 mask: mask, | |
| 6236 location: identifier); | 6287 location: identifier); |
| 6237 } else { | 6288 } else { |
| 6238 generateNonInstanceSetter( | 6289 generateNonInstanceSetter( |
| 6239 null, variable, value, location: identifier); | 6290 null, variable, value, location: identifier); |
| 6240 } | 6291 } |
| 6241 pop(); // Pop the value pushed by the setter call. | 6292 pop(); // Pop the value pushed by the setter call. |
| 6242 | 6293 |
| 6243 visit(node.body); | 6294 visit(node.body); |
| 6244 } | 6295 } |
| 6245 | 6296 |
| 6246 void buildUpdate() {}; | 6297 void buildUpdate() {}; |
| 6247 | 6298 |
| 6248 buildProtectedByFinally(() { | 6299 buildProtectedByFinally(() { |
| 6249 handleLoop(node, | 6300 handleLoop(node, |
| 6250 buildInitializer, | 6301 buildInitializer, |
| 6251 buildCondition, | 6302 buildCondition, |
| 6252 buildUpdate, | 6303 buildUpdate, |
| 6253 buildBody); | 6304 buildBody); |
| 6254 }, () { | 6305 }, () { |
| 6255 pushInvokeDynamic(node, new Selector.call("cancel", null, 0), | 6306 pushInvokeDynamic(node, |
| 6307 new Selector.call("cancel", null, 0), | |
| 6308 null, | |
| 6256 [streamIterator]); | 6309 [streamIterator]); |
| 6257 push(new HAwait(pop(), new TypeMask.subclass(compiler.objectClass, | 6310 push(new HAwait(pop(), new TypeMask.subclass(compiler.objectClass, |
| 6258 compiler.world))); | 6311 compiler.world))); |
| 6259 pop(); | 6312 pop(); |
| 6260 }); | 6313 }); |
| 6261 } | 6314 } |
| 6262 | 6315 |
| 6263 visitSyncForIn(ast.SyncForIn node) { | 6316 visitSyncForIn(ast.SyncForIn node) { |
| 6264 // The 'get iterator' selector for this node has the inferred receiver type. | 6317 // The 'get iterator' selector for this node has the inferred receiver type. |
| 6265 // If the receiver supports JavaScript indexing we generate an indexing loop | 6318 // If the receiver supports JavaScript indexing we generate an indexing loop |
| 6266 // instead of allocating an iterator object. | 6319 // instead of allocating an iterator object. |
| 6267 | 6320 |
| 6268 // This scheme recognizes for-in on direct lists. It does not recognize all | 6321 // This scheme recognizes for-in on direct lists. It does not recognize all |
| 6269 // uses of ArrayIterator. They still occur when the receiver is an Iterable | 6322 // uses of ArrayIterator. They still occur when the receiver is an Iterable |
| 6270 // with a `get iterator` method that delegate to another Iterable and the | 6323 // with a `get iterator` method that delegate to another Iterable and the |
| 6271 // method is inlined. We would require full scalar replacement in that | 6324 // method is inlined. We would require full scalar replacement in that |
| 6272 // case. | 6325 // case. |
| 6273 | 6326 |
| 6274 Selector selector = elements.getIteratorSelector(node); | 6327 Selector selector = elements.getIteratorSelector(node); |
| 6275 TypeMask mask = selector.mask; | 6328 TypeMask mask = elements.getIteratorTypeMask(node); |
| 6276 | 6329 |
| 6277 ClassWorld classWorld = compiler.world; | 6330 ClassWorld classWorld = compiler.world; |
| 6278 if (mask != null && mask.satisfies(backend.jsIndexableClass, classWorld)) { | 6331 if (mask != null && mask.satisfies(backend.jsIndexableClass, classWorld)) { |
| 6279 return buildSyncForInIndexable(node, mask); | 6332 return buildSyncForInIndexable(node, mask); |
| 6280 } | 6333 } |
| 6281 buildSyncForInIterator(node); | 6334 buildSyncForInIterator(node); |
| 6282 } | 6335 } |
| 6283 | 6336 |
| 6284 buildSyncForInIterator(ast.SyncForIn node) { | 6337 buildSyncForInIterator(ast.SyncForIn node) { |
| 6285 // Generate a structure equivalent to: | 6338 // Generate a structure equivalent to: |
| 6286 // Iterator<E> $iter = <iterable>.iterator; | 6339 // Iterator<E> $iter = <iterable>.iterator; |
| 6287 // while ($iter.moveNext()) { | 6340 // while ($iter.moveNext()) { |
| 6288 // <declaredIdentifier> = $iter.current; | 6341 // <declaredIdentifier> = $iter.current; |
| 6289 // <body> | 6342 // <body> |
| 6290 // } | 6343 // } |
| 6291 | 6344 |
| 6292 // The iterator is shared between initializer, condition and body. | 6345 // The iterator is shared between initializer, condition and body. |
| 6293 HInstruction iterator; | 6346 HInstruction iterator; |
| 6294 | 6347 |
| 6295 void buildInitializer() { | 6348 void buildInitializer() { |
| 6296 Selector selector = elements.getIteratorSelector(node); | 6349 Selector selector = elements.getIteratorSelector(node); |
| 6350 TypeMask mask = elements.getIteratorTypeMask(node); | |
| 6297 visit(node.expression); | 6351 visit(node.expression); |
| 6298 HInstruction receiver = pop(); | 6352 HInstruction receiver = pop(); |
| 6299 pushInvokeDynamic(node, selector, [receiver]); | 6353 pushInvokeDynamic(node, selector, mask, [receiver]); |
| 6300 iterator = pop(); | 6354 iterator = pop(); |
| 6301 } | 6355 } |
| 6302 | 6356 |
| 6303 HInstruction buildCondition() { | 6357 HInstruction buildCondition() { |
| 6304 Selector selector = elements.getMoveNextSelector(node); | 6358 Selector selector = elements.getMoveNextSelector(node); |
| 6305 pushInvokeDynamic(node, selector, [iterator]); | 6359 TypeMask mask = elements.getMoveNextTypeMask(node); |
| 6360 pushInvokeDynamic(node, selector, mask, [iterator]); | |
| 6306 return popBoolified(); | 6361 return popBoolified(); |
| 6307 } | 6362 } |
| 6308 | 6363 |
| 6309 void buildBody() { | 6364 void buildBody() { |
| 6310 Selector call = elements.getCurrentSelector(node); | 6365 Selector call = elements.getCurrentSelector(node); |
| 6311 pushInvokeDynamic(node, call, [iterator]); | 6366 TypeMask mask = elements.getCurrentTypeMask(node); |
| 6367 pushInvokeDynamic(node, call, mask, [iterator]); | |
| 6312 buildAssignLoopVariable(node, pop()); | 6368 buildAssignLoopVariable(node, pop()); |
| 6313 visit(node.body); | 6369 visit(node.body); |
| 6314 } | 6370 } |
| 6315 | 6371 |
| 6316 handleLoop(node, buildInitializer, buildCondition, () {}, buildBody); | 6372 handleLoop(node, buildInitializer, buildCondition, () {}, buildBody); |
| 6317 } | 6373 } |
| 6318 | 6374 |
| 6319 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { | 6375 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { |
| 6320 ast.Node identifier = node.declaredIdentifier; | 6376 ast.Node identifier = node.declaredIdentifier; |
| 6321 Element variable = elements.getForInVariable(node); | 6377 Element variable = elements.getForInVariable(node); |
| 6322 Selector selector = elements.getSelector(identifier); | 6378 Selector selector = elements.getSelector(identifier); |
| 6379 TypeMask mask = elements.getTypeMask(identifier); | |
| 6323 | 6380 |
| 6324 if (identifier.asSend() != null && | 6381 if (identifier.asSend() != null && |
| 6325 Elements.isInstanceSend(identifier, elements)) { | 6382 Elements.isInstanceSend(identifier, elements)) { |
| 6326 HInstruction receiver = generateInstanceSendReceiver(identifier); | 6383 HInstruction receiver = generateInstanceSendReceiver(identifier); |
| 6327 assert(receiver != null); | 6384 assert(receiver != null); |
| 6328 generateInstanceSetterWithCompiledReceiver( | 6385 generateInstanceSetterWithCompiledReceiver( |
| 6329 null, | 6386 null, |
| 6330 receiver, | 6387 receiver, |
| 6331 value, | 6388 value, |
| 6332 selector: selector, | 6389 selector: selector, |
| 6390 mask: mask, | |
| 6333 location: identifier); | 6391 location: identifier); |
| 6334 } else { | 6392 } else { |
| 6335 generateNonInstanceSetter(null, variable, value, location: identifier); | 6393 generateNonInstanceSetter(null, variable, value, location: identifier); |
| 6336 } | 6394 } |
| 6337 pop(); // Discard the value pushed by the setter call. | 6395 pop(); // Discard the value pushed by the setter call. |
| 6338 } | 6396 } |
| 6339 | 6397 |
| 6340 buildSyncForInIndexable(ast.ForIn node, TypeMask arrayType) { | 6398 buildSyncForInIndexable(ast.ForIn node, TypeMask arrayType) { |
| 6341 // Generate a structure equivalent to: | 6399 // Generate a structure equivalent to: |
| 6342 // | 6400 // |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6402 // inserted the ConcurrentModificationError check as part of the | 6460 // inserted the ConcurrentModificationError check as part of the |
| 6403 // condition. It is not necessary on the first iteration since there is | 6461 // condition. It is not necessary on the first iteration since there is |
| 6404 // no code between calls to `get iterator` and `moveNext`, so the test is | 6462 // no code between calls to `get iterator` and `moveNext`, so the test is |
| 6405 // moved to the loop update. | 6463 // moved to the loop update. |
| 6406 | 6464 |
| 6407 // Find a type for the element. Use the element type of the indexer of the | 6465 // Find a type for the element. Use the element type of the indexer of the |
| 6408 // array, as this is stronger than the iterator's `get current` type, for | 6466 // array, as this is stronger than the iterator's `get current` type, for |
| 6409 // example, `get current` includes null. | 6467 // example, `get current` includes null. |
| 6410 // TODO(sra): The element type of a container type mask might be better. | 6468 // TODO(sra): The element type of a container type mask might be better. |
| 6411 Selector selector = new Selector.index(); | 6469 Selector selector = new Selector.index(); |
| 6412 Selector refined = new TypedSelector(arrayType, selector, compiler.world); | 6470 TypeMask type = TypeMaskFactory.inferredTypeForSelector( |
| 6413 TypeMask type = | 6471 selector, arrayType, compiler); |
| 6414 TypeMaskFactory.inferredTypeForSelector(refined, compiler); | |
| 6415 | 6472 |
| 6416 HInstruction index = localsHandler.readLocal(indexVariable); | 6473 HInstruction index = localsHandler.readLocal(indexVariable); |
| 6417 HInstruction value = new HIndex(array, index, null, type); | 6474 HInstruction value = new HIndex(array, index, null, type); |
| 6418 add(value); | 6475 add(value); |
| 6419 | 6476 |
| 6420 buildAssignLoopVariable(node, value); | 6477 buildAssignLoopVariable(node, value); |
| 6421 visit(node.body); | 6478 visit(node.body); |
| 6422 } | 6479 } |
| 6423 | 6480 |
| 6424 void buildUpdate() { | 6481 void buildUpdate() { |
| (...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7321 // conversions. | 7378 // conversions. |
| 7322 // 2. The value can be primitive, because the library stringifier has | 7379 // 2. The value can be primitive, because the library stringifier has |
| 7323 // fast-path code for most primitives. | 7380 // fast-path code for most primitives. |
| 7324 if (expression.canBePrimitive(compiler)) { | 7381 if (expression.canBePrimitive(compiler)) { |
| 7325 append(stringify(node, expression)); | 7382 append(stringify(node, expression)); |
| 7326 return; | 7383 return; |
| 7327 } | 7384 } |
| 7328 | 7385 |
| 7329 // If the `toString` method is guaranteed to return a string we can call it | 7386 // If the `toString` method is guaranteed to return a string we can call it |
| 7330 // directly. | 7387 // directly. |
| 7331 Selector selector = | 7388 Selector selector = new Selector.call('toString', null, 0); |
| 7332 new TypedSelector(expression.instructionType, | 7389 TypeMask type = TypeMaskFactory.inferredTypeForSelector( |
| 7333 new Selector.call('toString', null, 0), compiler.world); | 7390 selector, expression.instructionType, compiler); |
| 7334 TypeMask type = TypeMaskFactory.inferredTypeForSelector(selector, compiler); | |
| 7335 if (type.containsOnlyString(compiler.world)) { | 7391 if (type.containsOnlyString(compiler.world)) { |
| 7336 builder.pushInvokeDynamic(node, selector, <HInstruction>[expression]); | 7392 builder.pushInvokeDynamic( |
| 7393 node, selector, expression.instructionType, <HInstruction>[expression] ); | |
| 7337 append(builder.pop()); | 7394 append(builder.pop()); |
| 7338 return; | 7395 return; |
| 7339 } | 7396 } |
| 7340 | 7397 |
| 7341 append(stringify(node, expression)); | 7398 append(stringify(node, expression)); |
| 7342 } | 7399 } |
| 7343 | 7400 |
| 7344 void visitStringInterpolation(ast.StringInterpolation node) { | 7401 void visitStringInterpolation(ast.StringInterpolation node) { |
| 7345 node.visitChildren(this); | 7402 node.visitChildren(this); |
| 7346 } | 7403 } |
| (...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7872 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 7929 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
| 7873 unaliased.accept(this, builder); | 7930 unaliased.accept(this, builder); |
| 7874 } | 7931 } |
| 7875 | 7932 |
| 7876 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 7933 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
| 7877 JavaScriptBackend backend = builder.compiler.backend; | 7934 JavaScriptBackend backend = builder.compiler.backend; |
| 7878 ClassElement cls = backend.findHelper('DynamicRuntimeType'); | 7935 ClassElement cls = backend.findHelper('DynamicRuntimeType'); |
| 7879 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); | 7936 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
| 7880 } | 7937 } |
| 7881 } | 7938 } |
| OLD | NEW |