| 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 SsaCodeGeneratorTask extends CompilerTask { | 7 class SsaCodeGeneratorTask extends CompilerTask { |
| 8 | 8 |
| 9 final JavaScriptBackend backend; | 9 final JavaScriptBackend backend; |
| 10 | 10 |
| (...skipping 2198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2209 | 2209 |
| 2210 List<js.Expression> arguments = <js.Expression>[object, record]; | 2210 List<js.Expression> arguments = <js.Expression>[object, record]; |
| 2211 FunctionElement helper = | 2211 FunctionElement helper = |
| 2212 compiler.findHelper(const SourceString('isJsIndexable')); | 2212 compiler.findHelper(const SourceString('isJsIndexable')); |
| 2213 world.registerStaticUse(helper); | 2213 world.registerStaticUse(helper); |
| 2214 String helperName = backend.namer.isolateAccess(helper); | 2214 String helperName = backend.namer.isolateAccess(helper); |
| 2215 push(new js.Call(new js.VariableUse(helperName), arguments)); | 2215 push(new js.Call(new js.VariableUse(helperName), arguments)); |
| 2216 if (negative) push(new js.Prefix('!', pop())); | 2216 if (negative) push(new js.Prefix('!', pop())); |
| 2217 } | 2217 } |
| 2218 | 2218 |
| 2219 void checkType(HInstruction input, HInstruction interceptor, | 2219 void checkType(HInstruction input, DartType type, {bool negative: false}) { |
| 2220 DartType type, {bool negative: false}) { | |
| 2221 Element element = type.element; | 2220 Element element = type.element; |
| 2222 if (element == backend.jsArrayClass) { | 2221 if (element == backend.jsArrayClass) { |
| 2223 checkArray(input, negative ? '!==': '==='); | 2222 checkArray(input, negative ? '!==': '==='); |
| 2224 return; | 2223 return; |
| 2225 } else if (element == backend.jsMutableArrayClass) { | 2224 } else if (element == backend.jsMutableArrayClass) { |
| 2226 if (negative) { | 2225 if (negative) { |
| 2227 checkImmutableArray(input); | 2226 checkImmutableArray(input); |
| 2228 } else { | 2227 } else { |
| 2229 checkMutableArray(input); | 2228 checkMutableArray(input); |
| 2230 } | 2229 } |
| 2231 return; | 2230 return; |
| 2232 } else if (element == backend.jsExtendableArrayClass) { | 2231 } else if (element == backend.jsExtendableArrayClass) { |
| 2233 if (negative) { | 2232 if (negative) { |
| 2234 checkFixedArray(input); | 2233 checkFixedArray(input); |
| 2235 } else { | 2234 } else { |
| 2236 checkExtendableArray(input); | 2235 checkExtendableArray(input); |
| 2237 } | 2236 } |
| 2238 return; | 2237 return; |
| 2239 } else if (element == backend.jsFixedArrayClass) { | 2238 } else if (element == backend.jsFixedArrayClass) { |
| 2240 if (negative) { | 2239 if (negative) { |
| 2241 checkExtendableArray(input); | 2240 checkExtendableArray(input); |
| 2242 } else { | 2241 } else { |
| 2243 checkFixedArray(input); | 2242 checkFixedArray(input); |
| 2244 } | 2243 } |
| 2245 return; | 2244 return; |
| 2246 } | 2245 } |
| 2247 use(interceptor); | 2246 use(input); |
| 2248 | 2247 |
| 2248 // Hack in interceptor. Ideally the interceptor would occur at the |
| 2249 // instruction level to allow optimizations, and checks would be broken into |
| 2250 // several smaller tests. |
| 2251 // This code is a slice of visitInterceptor for the univeral interceptor. |
| 2252 String interceptorName = backend.namer.getInterceptorName( |
| 2253 backend.getInterceptorMethod, backend.interceptedClasses); |
| 2254 backend.registerSpecializedGetInterceptor(backend.interceptedClasses); |
| 2255 backend.registerUseInterceptor(world); |
| 2256 |
| 2257 var isolate = new js.VariableUse(backend.namer.CURRENT_ISOLATE); |
| 2258 List<js.Expression> arguments = <js.Expression>[pop()]; |
| 2259 push(jsPropertyCall(isolate, interceptorName, arguments)); |
| 2249 world.registerIsCheck(type, work.resolutionTree); | 2260 world.registerIsCheck(type, work.resolutionTree); |
| 2250 | 2261 |
| 2251 js.PropertyAccess field = | 2262 js.PropertyAccess field = |
| 2252 new js.PropertyAccess.field(pop(), backend.namer.operatorIsType(type)); | 2263 new js.PropertyAccess.field(pop(), backend.namer.operatorIsType(type)); |
| 2253 // We always negate at least once so that the result is boolified. | 2264 // We always negate at least once so that the result is boolified. |
| 2254 push(new js.Prefix('!', field)); | 2265 push(new js.Prefix('!', field)); |
| 2255 // If the result is not negated, put another '!' in front. | 2266 // If the result is not negated, put another '!' in front. |
| 2256 if (!negative) push(new js.Prefix('!', pop())); | 2267 if (!negative) push(new js.Prefix('!', pop())); |
| 2257 } | 2268 } |
| 2258 | 2269 |
| 2259 void handleNumberOrStringSupertypeCheck(HInstruction input, | 2270 void handleNumberOrStringSupertypeCheck(HInstruction input, |
| 2260 HInstruction interceptor, | |
| 2261 DartType type, | 2271 DartType type, |
| 2262 { bool negative: false }) { | 2272 { bool negative: false }) { |
| 2263 assert(!identical(type.element, compiler.listClass) | 2273 assert(!identical(type.element, compiler.listClass) |
| 2264 && !Elements.isListSupertype(type.element, compiler) | 2274 && !Elements.isListSupertype(type.element, compiler) |
| 2265 && !Elements.isStringOnlySupertype(type.element, compiler)); | 2275 && !Elements.isStringOnlySupertype(type.element, compiler)); |
| 2266 String relation = negative ? '!==' : '==='; | 2276 String relation = negative ? '!==' : '==='; |
| 2267 checkNum(input, relation); | 2277 checkNum(input, relation); |
| 2268 js.Expression numberTest = pop(); | 2278 js.Expression numberTest = pop(); |
| 2269 checkString(input, relation); | 2279 checkString(input, relation); |
| 2270 js.Expression stringTest = pop(); | 2280 js.Expression stringTest = pop(); |
| 2271 checkObject(input, relation); | 2281 checkObject(input, relation); |
| 2272 js.Expression objectTest = pop(); | 2282 js.Expression objectTest = pop(); |
| 2273 checkType(input, interceptor, type, negative: negative); | 2283 checkType(input, type, negative: negative); |
| 2274 String combiner = negative ? '&&' : '||'; | 2284 String combiner = negative ? '&&' : '||'; |
| 2275 String combiner2 = negative ? '||' : '&&'; | 2285 String combiner2 = negative ? '||' : '&&'; |
| 2276 push(new js.Binary(combiner, | 2286 push(new js.Binary(combiner, |
| 2277 new js.Binary(combiner, numberTest, stringTest), | 2287 new js.Binary(combiner, numberTest, stringTest), |
| 2278 new js.Binary(combiner2, objectTest, pop()))); | 2288 new js.Binary(combiner2, objectTest, pop()))); |
| 2279 } | 2289 } |
| 2280 | 2290 |
| 2281 void handleStringSupertypeCheck(HInstruction input, | 2291 void handleStringSupertypeCheck(HInstruction input, |
| 2282 HInstruction interceptor, | |
| 2283 DartType type, | 2292 DartType type, |
| 2284 { bool negative: false }) { | 2293 { bool negative: false }) { |
| 2285 assert(!identical(type.element, compiler.listClass) | 2294 assert(!identical(type.element, compiler.listClass) |
| 2286 && !Elements.isListSupertype(type.element, compiler) | 2295 && !Elements.isListSupertype(type.element, compiler) |
| 2287 && !Elements.isNumberOrStringSupertype(type.element, compiler)); | 2296 && !Elements.isNumberOrStringSupertype(type.element, compiler)); |
| 2288 String relation = negative ? '!==' : '==='; | 2297 String relation = negative ? '!==' : '==='; |
| 2289 checkString(input, relation); | 2298 checkString(input, relation); |
| 2290 js.Expression stringTest = pop(); | 2299 js.Expression stringTest = pop(); |
| 2291 checkObject(input, relation); | 2300 checkObject(input, relation); |
| 2292 js.Expression objectTest = pop(); | 2301 js.Expression objectTest = pop(); |
| 2293 checkType(input, interceptor, type, negative: negative); | 2302 checkType(input, type, negative: negative); |
| 2294 String combiner = negative ? '||' : '&&'; | 2303 String combiner = negative ? '||' : '&&'; |
| 2295 push(new js.Binary(negative ? '&&' : '||', | 2304 push(new js.Binary(negative ? '&&' : '||', |
| 2296 stringTest, | 2305 stringTest, |
| 2297 new js.Binary(combiner, objectTest, pop()))); | 2306 new js.Binary(combiner, objectTest, pop()))); |
| 2298 } | 2307 } |
| 2299 | 2308 |
| 2300 void handleListOrSupertypeCheck(HInstruction input, | 2309 void handleListOrSupertypeCheck(HInstruction input, |
| 2301 HInstruction interceptor, | |
| 2302 DartType type, | 2310 DartType type, |
| 2303 { bool negative: false }) { | 2311 { bool negative: false }) { |
| 2304 assert(!identical(type.element, compiler.stringClass) | 2312 assert(!identical(type.element, compiler.stringClass) |
| 2305 && !Elements.isStringOnlySupertype(type.element, compiler) | 2313 && !Elements.isStringOnlySupertype(type.element, compiler) |
| 2306 && !Elements.isNumberOrStringSupertype(type.element, compiler)); | 2314 && !Elements.isNumberOrStringSupertype(type.element, compiler)); |
| 2307 String relation = negative ? '!==' : '==='; | 2315 String relation = negative ? '!==' : '==='; |
| 2308 checkObject(input, relation); | 2316 checkObject(input, relation); |
| 2309 js.Expression objectTest = pop(); | 2317 js.Expression objectTest = pop(); |
| 2310 checkArray(input, relation); | 2318 checkArray(input, relation); |
| 2311 js.Expression arrayTest = pop(); | 2319 js.Expression arrayTest = pop(); |
| 2312 checkType(input, interceptor, type, negative: negative); | 2320 checkType(input, type, negative: negative); |
| 2313 String combiner = negative ? '&&' : '||'; | 2321 String combiner = negative ? '&&' : '||'; |
| 2314 push(new js.Binary(negative ? '||' : '&&', | 2322 push(new js.Binary(negative ? '||' : '&&', |
| 2315 objectTest, | 2323 objectTest, |
| 2316 new js.Binary(combiner, arrayTest, pop()))); | 2324 new js.Binary(combiner, arrayTest, pop()))); |
| 2317 } | 2325 } |
| 2318 | 2326 |
| 2319 void visitIs(HIs node) { | 2327 void visitIs(HIs node) { |
| 2320 emitIs(node, "==="); | 2328 emitIs(node, "==="); |
| 2321 } | 2329 } |
| 2322 | 2330 |
| 2323 void emitIs(HIs node, String relation) { | 2331 void emitIs(HIs node, String relation) { |
| 2324 DartType type = node.typeExpression; | 2332 DartType type = node.typeExpression; |
| 2325 world.registerIsCheck(type, work.resolutionTree); | 2333 world.registerIsCheck(type, work.resolutionTree); |
| 2326 HInstruction input = node.expression; | 2334 HInstruction input = node.expression; |
| 2327 | 2335 |
| 2328 // If this is changed to single == there are several places below that must | 2336 // If this is changed to single == there are several places below that must |
| 2329 // be changed to match. | 2337 // be changed to match. |
| 2330 assert(relation == '===' || relation == '!=='); | 2338 assert(relation == '===' || relation == '!=='); |
| 2331 bool negative = relation == '!=='; | 2339 bool negative = relation == '!=='; |
| 2332 | 2340 |
| 2333 if (node.isVariableCheck || node.isCompoundCheck) { | 2341 if (node.isVariableCheck || node.isCompoundCheck) { |
| 2334 use(node.checkCall); | 2342 use(node.checkCall); |
| 2335 if (negative) push(new js.Prefix('!', pop())); | 2343 if (negative) push(new js.Prefix('!', pop())); |
| 2336 } else { | 2344 } else { |
| 2337 assert(node.isRawCheck); | 2345 assert(node.isRawCheck); |
| 2338 HInstruction interceptor = node.interceptor; | |
| 2339 LibraryElement coreLibrary = compiler.coreLibrary; | 2346 LibraryElement coreLibrary = compiler.coreLibrary; |
| 2340 ClassElement objectClass = compiler.objectClass; | 2347 ClassElement objectClass = compiler.objectClass; |
| 2341 Element element = type.element; | 2348 Element element = type.element; |
| 2342 if (element == compiler.nullClass) { | 2349 if (element == compiler.nullClass) { |
| 2343 if (negative) { | 2350 if (negative) { |
| 2344 checkNonNull(input); | 2351 checkNonNull(input); |
| 2345 } else { | 2352 } else { |
| 2346 checkNull(input); | 2353 checkNull(input); |
| 2347 } | 2354 } |
| 2348 } else if (identical(element, objectClass) || type.treatAsDynamic) { | 2355 } else if (identical(element, objectClass) || type.treatAsDynamic) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2363 attachLocationToLast(node); | 2370 attachLocationToLast(node); |
| 2364 } else if (element == compiler.intClass) { | 2371 } else if (element == compiler.intClass) { |
| 2365 // The is check in the code tells us that it might not be an | 2372 // The is check in the code tells us that it might not be an |
| 2366 // int. So we do a typeof first to avoid possible | 2373 // int. So we do a typeof first to avoid possible |
| 2367 // deoptimizations on the JS engine due to the Math.floor check. | 2374 // deoptimizations on the JS engine due to the Math.floor check. |
| 2368 checkNum(input, relation); | 2375 checkNum(input, relation); |
| 2369 js.Expression numTest = pop(); | 2376 js.Expression numTest = pop(); |
| 2370 checkBigInt(input, relation); | 2377 checkBigInt(input, relation); |
| 2371 push(new js.Binary(negative ? '||' : '&&', numTest, pop()), node); | 2378 push(new js.Binary(negative ? '||' : '&&', numTest, pop()), node); |
| 2372 } else if (Elements.isNumberOrStringSupertype(element, compiler)) { | 2379 } else if (Elements.isNumberOrStringSupertype(element, compiler)) { |
| 2373 handleNumberOrStringSupertypeCheck( | 2380 handleNumberOrStringSupertypeCheck(input, type, negative: negative); |
| 2374 input, interceptor, type, negative: negative); | |
| 2375 attachLocationToLast(node); | 2381 attachLocationToLast(node); |
| 2376 } else if (Elements.isStringOnlySupertype(element, compiler)) { | 2382 } else if (Elements.isStringOnlySupertype(element, compiler)) { |
| 2377 handleStringSupertypeCheck( | 2383 handleStringSupertypeCheck(input, type, negative: negative); |
| 2378 input, interceptor, type, negative: negative); | |
| 2379 attachLocationToLast(node); | 2384 attachLocationToLast(node); |
| 2380 } else if (identical(element, compiler.listClass) | 2385 } else if (identical(element, compiler.listClass) |
| 2381 || Elements.isListSupertype(element, compiler)) { | 2386 || Elements.isListSupertype(element, compiler)) { |
| 2382 handleListOrSupertypeCheck( | 2387 handleListOrSupertypeCheck(input, type, negative: negative); |
| 2383 input, interceptor, type, negative: negative); | |
| 2384 attachLocationToLast(node); | 2388 attachLocationToLast(node); |
| 2385 } else if (type.kind == TypeKind.FUNCTION) { | 2389 } else if (element.isTypedef()) { |
| 2386 checkType(input, interceptor, type, negative: negative); | 2390 if (negative) { |
| 2391 checkNull(input); |
| 2392 } else { |
| 2393 checkNonNull(input); |
| 2394 } |
| 2395 js.Expression nullTest = pop(); |
| 2396 checkType(input, type, negative: negative); |
| 2397 push(new js.Binary(negative ? '||' : '&&', nullTest, pop())); |
| 2387 attachLocationToLast(node); | 2398 attachLocationToLast(node); |
| 2388 } else if ((input.canBePrimitive(compiler) | 2399 } else if ((input.canBePrimitive(compiler) |
| 2389 && !input.canBePrimitiveArray(compiler)) | 2400 && !input.canBePrimitiveArray(compiler)) |
| 2390 || input.canBeNull()) { | 2401 || input.canBeNull()) { |
| 2391 checkObject(input, relation); | 2402 checkObject(input, relation); |
| 2392 js.Expression objectTest = pop(); | 2403 js.Expression objectTest = pop(); |
| 2393 checkType(input, interceptor, type, negative: negative); | 2404 checkType(input, type, negative: negative); |
| 2394 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()), node); | 2405 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()), node); |
| 2395 } else { | 2406 } else { |
| 2396 checkType(input, interceptor, type, negative: negative); | 2407 checkType(input, type, negative: negative); |
| 2397 attachLocationToLast(node); | 2408 attachLocationToLast(node); |
| 2398 } | 2409 } |
| 2399 } | 2410 } |
| 2411 if (node.nullOk) { |
| 2412 if (negative) { |
| 2413 checkNonNull(input); |
| 2414 push(new js.Binary('&&', pop(), pop()), node); |
| 2415 } else { |
| 2416 checkNull(input); |
| 2417 push(new js.Binary('||', pop(), pop()), node); |
| 2418 } |
| 2419 } |
| 2400 } | 2420 } |
| 2401 | 2421 |
| 2402 js.Expression generateTest(HCheck node) { | 2422 js.Expression generateTest(HCheck node) { |
| 2403 HInstruction input = node.checkedInput; | 2423 HInstruction input = node.checkedInput; |
| 2404 TypeMask receiver = input.instructionType.computeMask(compiler); | 2424 TypeMask receiver = input.instructionType.computeMask(compiler); |
| 2405 TypeMask mask = node.instructionType.computeMask(compiler); | 2425 TypeMask mask = node.instructionType.computeMask(compiler); |
| 2406 bool turnIntoNullCheck = mask.nullable() == receiver; | 2426 bool turnIntoNullCheck = mask.nullable() == receiver; |
| 2407 js.Expression test; | 2427 js.Expression test; |
| 2408 if (turnIntoNullCheck) { | 2428 if (turnIntoNullCheck) { |
| 2409 use(input); | 2429 use(input); |
| (...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2969 if (leftType.canBeNull() && rightType.canBeNull()) { | 2989 if (leftType.canBeNull() && rightType.canBeNull()) { |
| 2970 if (left.isConstantNull() || right.isConstantNull() || | 2990 if (left.isConstantNull() || right.isConstantNull() || |
| 2971 (leftType.isPrimitive(compiler) && leftType == rightType)) { | 2991 (leftType.isPrimitive(compiler) && leftType == rightType)) { |
| 2972 return '=='; | 2992 return '=='; |
| 2973 } | 2993 } |
| 2974 return null; | 2994 return null; |
| 2975 } else { | 2995 } else { |
| 2976 return '==='; | 2996 return '==='; |
| 2977 } | 2997 } |
| 2978 } | 2998 } |
| OLD | NEW |