2196 * 2197 * @return the method emitter 2198 */ 2199 MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) { 2200 debug("dynamic_runtime_call", name, "args=", request.getArity(), "returnType=", returnType); 2201 final String signature = getDynamicSignature(returnType, request.getArity()); 2202 debug(" signature", signature); 2203 method.visitInvokeDynamicInsn(name, signature, RUNTIMEBOOTSTRAP); 2204 pushType(returnType); 2205 2206 return this; 2207 } 2208 2209 /** 2210 * Generate dynamic getter. Pop scope from stack. Push result 2211 * 2212 * @param valueType type of the value to set 2213 * @param name name of property 2214 * @param flags call site flags 2215 * @param isMethod should it prefer retrieving methods 2216 * 2217 * @return the method emitter 2218 */ 2219 MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) { 2220 if (name.length() > LARGE_STRING_THRESHOLD) { // use getIndex for extremely long names 2221 return load(name).dynamicGetIndex(valueType, flags, isMethod); 2222 } 2223 2224 debug("dynamic_get", name, valueType, getProgramPoint(flags)); 2225 2226 Type type = valueType; 2227 if (type.isObject() || type.isBoolean()) { 2228 type = Type.OBJECT; //promote e.g strings to object generic setter 2229 } 2230 2231 popType(Type.SCOPE); 2232 method.visitInvokeDynamicInsn((isMethod ? "dyn:getMethod|getProp|getElem:" : "dyn:getProp|getElem|getMethod:") + 2233 NameCodec.encode(name), Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags); 2234 2235 pushType(type); 2236 convert(valueType); //most probably a nop 2237 2238 return this; 2239 } 2240 2241 /** 2242 * Generate dynamic setter. Pop receiver and property from stack. 2243 * 2244 * @param name name of property 2245 * @param flags call site flags 2246 */ 2247 void dynamicSet(final String name, final int flags) { 2248 if (name.length() > LARGE_STRING_THRESHOLD) { // use setIndex for extremely long names 2249 load(name).swap().dynamicSetIndex(flags); 2250 return; 2251 } 2252 2253 assert !isOptimistic(flags); 2254 debug("dynamic_set", name, peekType()); 2255 2256 Type type = peekType(); 2257 if (type.isObject() || type.isBoolean()) { //promote strings to objects etc 2258 type = Type.OBJECT; 2259 convert(Type.OBJECT); //TODO bad- until we specialize boolean setters, 2260 } 2261 popType(type); 2262 popType(Type.SCOPE); 2263 2264 method.visitInvokeDynamicInsn("dyn:setProp|setElem:" + NameCodec.encode(name), methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags); 2265 } 2266 2267 /** 2268 * Dynamic getter for indexed structures. Pop index and receiver from stack, 2269 * generate appropriate signatures based on types 2270 * 2271 * @param result result type for getter 2272 * @param flags call site flags for getter 2273 * @param isMethod should it prefer retrieving methods 2274 * 2275 * @return the method emitter 2276 */ 2277 MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) { 2278 assert result.getTypeClass().isPrimitive() || result.getTypeClass() == Object.class; 2279 debug("dynamic_get_index", peekType(1), "[", peekType(), "]", getProgramPoint(flags)); 2280 2281 Type resultType = result; 2282 if (result.isBoolean()) { 2283 resultType = Type.OBJECT; // INT->OBJECT to avoid another dimension of cross products in the getters. TODO 2284 } 2285 2286 Type index = peekType(); 2287 if (index.isObject() || index.isBoolean()) { 2288 index = Type.OBJECT; //e.g. string->object 2289 convert(Type.OBJECT); 2290 } 2291 popType(); 2292 2293 popType(Type.OBJECT); 2294 2295 final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index); 2296 2297 method.visitInvokeDynamicInsn(isMethod ? "dyn:getMethod|getElem|getProp" : "dyn:getElem|getProp|getMethod", signature, LINKERBOOTSTRAP, flags); 2298 pushType(resultType); 2299 2300 if (result.isBoolean()) { 2301 convert(Type.BOOLEAN); 2302 } 2303 2304 return this; 2305 } 2306 2307 private static String getProgramPoint(final int flags) { 2308 if((flags & CALLSITE_OPTIMISTIC) == 0) { 2309 return ""; 2310 } 2311 return "pp=" + String.valueOf((flags & (-1 << CALLSITE_PROGRAM_POINT_SHIFT)) >> CALLSITE_PROGRAM_POINT_SHIFT); 2312 } 2313 2314 /** 2315 * Dynamic setter for indexed structures. Pop value, index and receiver from 2316 * stack, generate appropriate signature based on types 2317 * 2489 while(next != null) { 2490 final Symbol symbol = next.getSymbol(); 2491 if(next.isLive()) { 2492 emitLocalVariableConversion(next, true); 2493 } else { 2494 markDeadLocalVariable(symbol); 2495 } 2496 next = next.getNext(); 2497 } 2498 } 2499 2500 void beforeTry(final TryNode tryNode, final Label recovery) { 2501 LocalVariableConversion next = tryNode.getLocalVariableConversion(); 2502 while(next != null) { 2503 if(next.isLive()) { 2504 final Type to = emitLocalVariableConversion(next, false); 2505 recovery.getStack().onLocalStore(to, next.getSymbol().getSlot(to), true); 2506 } 2507 next = next.getNext(); 2508 } 2509 } 2510 2511 private Type emitLocalVariableConversion(final LocalVariableConversion conversion, final boolean onlySymbolLiveValue) { 2512 final Type from = conversion.getFrom(); 2513 final Type to = conversion.getTo(); 2514 final Symbol symbol = conversion.getSymbol(); 2515 assert symbol.isBytecodeLocal(); 2516 if(from == Type.UNDEFINED) { 2517 loadUndefined(to); 2518 } else { 2519 load(symbol, from).convert(to); 2520 } 2521 store(symbol, to, onlySymbolLiveValue); 2522 return to; 2523 } 2524 2525 /* 2526 * Debugging below 2527 */ 2528 | 2196 * 2197 * @return the method emitter 2198 */ 2199 MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) { 2200 debug("dynamic_runtime_call", name, "args=", request.getArity(), "returnType=", returnType); 2201 final String signature = getDynamicSignature(returnType, request.getArity()); 2202 debug(" signature", signature); 2203 method.visitInvokeDynamicInsn(name, signature, RUNTIMEBOOTSTRAP); 2204 pushType(returnType); 2205 2206 return this; 2207 } 2208 2209 /** 2210 * Generate dynamic getter. Pop scope from stack. Push result 2211 * 2212 * @param valueType type of the value to set 2213 * @param name name of property 2214 * @param flags call site flags 2215 * @param isMethod should it prefer retrieving methods 2216 * @param isIndex is this an index operation? 2217 * @return the method emitter 2218 */ 2219 MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod, final boolean isIndex) { 2220 if (name.length() > LARGE_STRING_THRESHOLD) { // use getIndex for extremely long names 2221 return load(name).dynamicGetIndex(valueType, flags, isMethod); 2222 } 2223 2224 debug("dynamic_get", name, valueType, getProgramPoint(flags)); 2225 2226 Type type = valueType; 2227 if (type.isObject() || type.isBoolean()) { 2228 type = Type.OBJECT; //promote e.g strings to object generic setter 2229 } 2230 2231 popType(Type.SCOPE); 2232 method.visitInvokeDynamicInsn(dynGetOperation(isMethod, isIndex) + ':' + NameCodec.encode(name), 2233 Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags); 2234 2235 pushType(type); 2236 convert(valueType); //most probably a nop 2237 2238 return this; 2239 } 2240 2241 /** 2242 * Generate dynamic setter. Pop receiver and property from stack. 2243 * 2244 * @param name name of property 2245 * @param flags call site flags 2246 * @param isIndex is this an index operation? 2247 */ 2248 void dynamicSet(final String name, final int flags, final boolean isIndex) { 2249 if (name.length() > LARGE_STRING_THRESHOLD) { // use setIndex for extremely long names 2250 load(name).swap().dynamicSetIndex(flags); 2251 return; 2252 } 2253 2254 assert !isOptimistic(flags); 2255 debug("dynamic_set", name, peekType()); 2256 2257 Type type = peekType(); 2258 if (type.isObject() || type.isBoolean()) { //promote strings to objects etc 2259 type = Type.OBJECT; 2260 convert(Type.OBJECT); //TODO bad- until we specialize boolean setters, 2261 } 2262 popType(type); 2263 popType(Type.SCOPE); 2264 2265 method.visitInvokeDynamicInsn(dynSetOperation(isIndex) + ':' + NameCodec.encode(name), 2266 methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags); 2267 } 2268 2269 /** 2270 * Dynamic getter for indexed structures. Pop index and receiver from stack, 2271 * generate appropriate signatures based on types 2272 * 2273 * @param result result type for getter 2274 * @param flags call site flags for getter 2275 * @param isMethod should it prefer retrieving methods 2276 * 2277 * @return the method emitter 2278 */ 2279 MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) { 2280 assert result.getTypeClass().isPrimitive() || result.getTypeClass() == Object.class; 2281 debug("dynamic_get_index", peekType(1), "[", peekType(), "]", getProgramPoint(flags)); 2282 2283 Type resultType = result; 2284 if (result.isBoolean()) { 2285 resultType = Type.OBJECT; // INT->OBJECT to avoid another dimension of cross products in the getters. TODO 2286 } 2287 2288 Type index = peekType(); 2289 if (index.isObject() || index.isBoolean()) { 2290 index = Type.OBJECT; //e.g. string->object 2291 convert(Type.OBJECT); 2292 } 2293 popType(); 2294 2295 popType(Type.OBJECT); 2296 2297 final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index); 2298 2299 method.visitInvokeDynamicInsn(dynGetOperation(isMethod, true), signature, LINKERBOOTSTRAP, flags); 2300 pushType(resultType); 2301 2302 if (result.isBoolean()) { 2303 convert(Type.BOOLEAN); 2304 } 2305 2306 return this; 2307 } 2308 2309 private static String getProgramPoint(final int flags) { 2310 if((flags & CALLSITE_OPTIMISTIC) == 0) { 2311 return ""; 2312 } 2313 return "pp=" + String.valueOf((flags & (-1 << CALLSITE_PROGRAM_POINT_SHIFT)) >> CALLSITE_PROGRAM_POINT_SHIFT); 2314 } 2315 2316 /** 2317 * Dynamic setter for indexed structures. Pop value, index and receiver from 2318 * stack, generate appropriate signature based on types 2319 * 2491 while(next != null) { 2492 final Symbol symbol = next.getSymbol(); 2493 if(next.isLive()) { 2494 emitLocalVariableConversion(next, true); 2495 } else { 2496 markDeadLocalVariable(symbol); 2497 } 2498 next = next.getNext(); 2499 } 2500 } 2501 2502 void beforeTry(final TryNode tryNode, final Label recovery) { 2503 LocalVariableConversion next = tryNode.getLocalVariableConversion(); 2504 while(next != null) { 2505 if(next.isLive()) { 2506 final Type to = emitLocalVariableConversion(next, false); 2507 recovery.getStack().onLocalStore(to, next.getSymbol().getSlot(to), true); 2508 } 2509 next = next.getNext(); 2510 } 2511 } 2512 2513 private static String dynGetOperation(final boolean isMethod, final boolean isIndex) { 2514 if (isMethod) { 2515 return isIndex ? "dyn:getMethod|getElem|getProp" : "dyn:getMethod|getProp|getElem"; 2516 } else { 2517 return isIndex ? "dyn:getElem|getProp|getMethod" : "dyn:getProp|getElem|getMethod"; 2518 } 2519 } 2520 2521 private static String dynSetOperation(final boolean isIndex) { 2522 return isIndex ? "dyn:setElem|setProp" : "dyn:setProp|setElem"; 2523 } 2524 2525 private Type emitLocalVariableConversion(final LocalVariableConversion conversion, final boolean onlySymbolLiveValue) { 2526 final Type from = conversion.getFrom(); 2527 final Type to = conversion.getTo(); 2528 final Symbol symbol = conversion.getSymbol(); 2529 assert symbol.isBytecodeLocal(); 2530 if(from == Type.UNDEFINED) { 2531 loadUndefined(to); 2532 } else { 2533 load(symbol, from).convert(to); 2534 } 2535 store(symbol, to, onlySymbolLiveValue); 2536 return to; 2537 } 2538 2539 /* 2540 * Debugging below 2541 */ 2542 |