| 1 4 package gnu.expr; 5 import gnu.bytecode.*; 6 import gnu.mapping.*; 7 import gnu.text.SourceMessages; 8 9 13 14 public class ApplyExp extends Expression 15 { 16 Expression func; 17 Expression[] args; 18 19 public static final int TAILCALL = NEXT_AVAIL_FLAG; 20 public static final int INLINE_IF_CONSTANT = NEXT_AVAIL_FLAG << 1; 21 22 23 LambdaExp context; 24 25 26 public ApplyExp nextCall; 27 28 public final Expression getFunction() { return func; } 29 public final Expression[] getArgs() { return args; } 30 public final int getArgCount() { return args.length; } 31 public void setFunction(Expression func) { this.func = func; } 32 public void setArgs(Expression[] args) { this.args = args; } 33 public Expression getArg(int i) { return args[i]; } 34 public void setArg(int i, Expression arg) { args[i] = arg; } 35 public final boolean isTailCall() { return getFlag(TAILCALL); } 36 public final void setTailCall(boolean tailCall) 37 { setFlag(tailCall, TAILCALL); } 38 39 40 public final Object getFunctionValue() 41 { 42 return func instanceof QuoteExp ? ((QuoteExp) func).getValue() : null; 43 } 44 45 public ApplyExp (Expression f, Expression[] a) { func = f; args = a; } 46 47 public ApplyExp (Procedure p, Expression[] a) { func = new QuoteExp(p); args = a; } 48 49 public ApplyExp (Method m, Expression[] a) 50 { 51 func = new QuoteExp(new PrimProcedure(m)); 52 args = a; 53 } 54 55 protected boolean mustCompile () { return false; } 56 57 public void apply (CallContext ctx) throws Throwable  58 { 59 Object proc = func.eval(ctx); 60 int n = args.length; 61 Object [] vals = new Object [n]; 62 for (int i = 0; i < n; i++) 63 vals[i] = args[i].eval(ctx); 64 ((Procedure) proc).checkN(vals, ctx); 65 } 66 67 public static void compileToArray(Expression[] args, Compilation comp) 68 { 69 CodeAttr code = comp.getCode(); 70 if (args.length == 0) 71 { 72 code.emitGetStatic(Compilation.noArgsField); 73 return; 74 } 75 code.emitPushInt(args.length); 76 code.emitNewArray(Type.pointer_type); 77 for (int i = 0; i < args.length; ++i) 78 { 79 Expression arg = args[i]; 80 if (comp.usingCPStyle() 81 && ! (arg instanceof QuoteExp) && ! (arg instanceof ReferenceExp)) 82 { 83 arg.compile (comp, Target.pushObject); 92 code.emitSwap(); 93 code.emitDup(1, 1); 94 code.emitSwap(); 95 code.emitPushInt(i); 96 code.emitSwap(); 97 } 98 else 99 { 100 code.emitDup(Compilation.objArrayType); 101 code.emitPushInt(i); 102 arg.compile (comp, Target.pushObject); 103 } 104 code.emitArrayStore(Type.pointer_type); 105 } 106 } 107 108 public void compile (Compilation comp, Target target) 109 { 110 compile(this, comp, target, true); 111 } 112 113 public static void compile (ApplyExp exp, Compilation comp, Target target) 114 { 115 compile(exp, comp, target, false); 116 } 117 118 static void compile (ApplyExp exp, Compilation comp, Target target, 119 boolean checkInlineable) 120 { 121 int args_length = exp.args.length; 122 Expression exp_func = exp.func; 123 LambdaExp func_lambda = null; 124 String func_name = null; 125 Declaration owner = null; 126 if (exp_func instanceof LambdaExp) 127 { 128 func_lambda = (LambdaExp) exp_func; 129 func_name = func_lambda.getName(); 130 if (func_name == null) 131 func_name = "<lambda>"; 132 } 133 else if (exp_func instanceof ReferenceExp) 134 { 135 ReferenceExp func_ref = (ReferenceExp) exp_func; 136 owner = func_ref.contextDecl(); 137 Declaration func_decl = func_ref.binding; 138 while (func_decl != null && func_decl.isAlias() 139 && func_decl.value instanceof ReferenceExp) 140 { 141 func_ref = (ReferenceExp) func_decl.value; 142 if (owner != null || func_decl.needsContext() || func_ref.binding == null) 143 break; 144 func_decl = func_ref.binding; 145 owner = func_ref.contextDecl(); 146 } 147 if (! func_decl.getFlag(Declaration.IS_UNKNOWN)) 148 { 149 Expression value = func_decl.getValue(); 150 func_name = func_decl.getName(); 151 if (value != null && value instanceof LambdaExp) 152 func_lambda = (LambdaExp) value; 153 if (value != null && value instanceof QuoteExp) 154 { 155 Object quotedValue = ((QuoteExp) value).getValue(); 156 if (checkInlineable && quotedValue instanceof Inlineable) 157 { 158 ((Inlineable) quotedValue).compile(exp, comp, target); 159 return; 160 } 161 } 162 } 163 } 164 else if (exp_func instanceof QuoteExp) 165 { 166 Object proc = ((QuoteExp) exp_func).getValue(); 167 if (proc instanceof Inlineable) 168 { 169 if (checkInlineable) 170 { 171 ((Inlineable) proc).compile(exp, comp, target); 172 return; 173 } 174 } 175 } 176 177 gnu.bytecode.CodeAttr code = comp.getCode(); 178 Method method; 179 180 if (func_lambda != null) 181 { 182 if ((func_lambda.max_args >= 0 && args_length > func_lambda.max_args) 183 || args_length < func_lambda.min_args) 184 throw new Error ("internal error - wrong number of parameters for " 186 + func_lambda); 187 int conv = func_lambda.getCallConvention(); 188 if (comp.inlineOk(func_lambda) 189 && (conv <= Compilation.CALL_WITH_CONSUMER 190 || (conv == Compilation.CALL_WITH_TAILCALLS 191 && ! exp.isTailCall())) 192 && (method = func_lambda.getMethod(args_length)) != null) 193 { 194 PrimProcedure pproc = new PrimProcedure(method, func_lambda); 195 boolean is_static = method.getStaticFlag(); 196 boolean extraArg = false; 197 if (! is_static || func_lambda.declareClosureEnv() != null) 199 { 200 if (is_static) 201 extraArg = true; 202 if (comp.curLambda == func_lambda) code.emitLoad(func_lambda.closureEnv != null 204 ? func_lambda.closureEnv 205 : func_lambda.thisVariable); 206 else if (owner != null) 207 owner.load(null, 0, comp, Target.pushObject); 208 else 209 func_lambda.getOwningLambda().loadHeapFrame(comp); 210 } 211 212 pproc.compile(extraArg ? Type.void_type : null, 213 exp, comp, target); 214 return; 215 } 216 } 217 218 if (comp.usingCPStyle()) 219 { 220 { 221 Label l = new Label(code); 222 gnu.bytecode.SwitchState fswitch = comp.fswitch; 223 int pc = fswitch.getMaxValue() + 1; 224 fswitch.addCase(pc, l, code); 225 exp_func.compile(comp, new StackTarget(Compilation.typeProcedure)); 226 comp.loadCallContext(); 227 228 comp.loadCallContext(); 230 code.emitPushInt(pc); 231 code.emitPutField(Compilation.pcCallContextField); 232 code.emitInvokeVirtual(Compilation.applyCpsMethod); 233 234 Type[] stackTypes = code.saveStackTypeState(false); 236 java.util.Stack stackFields = new java.util.Stack (); 237 if (stackTypes != null) 238 { 239 for (int i = stackTypes.length; --i >= 0; ) 240 { 241 Field fld = comp.allocLocalField (stackTypes[i], null); 242 code.emitPushThis(); 243 code.emitSwap(); 244 code.emitPutField(fld); 245 stackFields.push(fld); 246 } 247 } 248 249 code.emitReturn(); 250 l.define(code); 251 252 if (stackTypes != null) 254 { 255 for (int i = stackTypes.length; --i >= 0; ) 256 { 257 Field fld = (Field) stackFields.pop(); 258 code.emitPushThis(); 259 code.emitGetField(fld); 260 comp.freeLocalField(fld); 261 } 262 } 263 264 270 } 271 return; 272 } 273 274 boolean tail_recurse 276 = exp.isTailCall() 277 && func_lambda != null && func_lambda == comp.curLambda; 278 279 if (func_lambda != null && func_lambda.getInlineOnly() && !tail_recurse 280 && func_lambda.min_args == args_length) 281 { 282 pushArgs(func_lambda, exp.args, comp); 283 LambdaExp saveLambda = comp.curLambda; 284 comp.curLambda = func_lambda; 285 func_lambda.allocChildClasses(comp); 286 func_lambda.allocParameters(comp); 287 popParams (code, func_lambda, false); 288 func_lambda.enterFunction(comp); 289 func_lambda.body.compileWithPosition(comp, target); 290 func_lambda.compileEnd(comp); 291 func_lambda.compileChildMethods(comp); 292 func_lambda.popScope(code); 293 comp.curLambda = saveLambda; 294 return; 295 } 296 297 if (comp.curLambda.isHandlingTailCalls() 298 && (exp.isTailCall() || target instanceof ConsumerTarget) 299 && ! comp.curLambda.getInlineOnly()) 300 { 301 ClassType typeContext = Compilation.typeCallContext; 302 exp_func.compile(comp, new StackTarget(Compilation.typeProcedure)); 303 if (args_length <= 4) 305 { 306 for (int i = 0; i < args_length; ++i) 307 exp.args[i].compile(comp, Target.pushObject); 308 comp.loadCallContext(); 309 code.emitInvoke(Compilation.typeProcedure 310 .getDeclaredMethod("check"+args_length, 311 args_length+1)); 312 } 313 else 314 { 315 compileToArray (exp.args, comp); 316 comp.loadCallContext(); 317 code.emitInvoke(Compilation.typeProcedure 318 .getDeclaredMethod("checkN", 2)); 319 } 320 if (exp.isTailCall()) 321 { 322 code.emitReturn(); 323 } 324 else if (((ConsumerTarget) target).isContextTarget()) 325 { 326 comp.loadCallContext(); 327 code.emitInvoke(typeContext.getDeclaredMethod("runUntilDone", 0)); 328 } 329 else 330 { 331 comp.loadCallContext(); 332 code.emitLoad(((ConsumerTarget) target).getConsumerVariable()); 333 code.emitInvoke(typeContext.getDeclaredMethod("runUntilValue", 1)); 334 } 335 return; 336 } 337 338 if (!tail_recurse) 339 exp_func.compile (comp, new StackTarget(Compilation.typeProcedure)); 340 341 boolean toArray 342 = (tail_recurse ? func_lambda.min_args != func_lambda.max_args 343 : args_length > 4); 344 if (toArray) 345 { 346 compileToArray(exp.args, comp); 347 method = Compilation.applyNmethod; 348 } 349 else if (tail_recurse) 350 { 351 pushArgs(func_lambda, exp.args, comp); 352 method = null; 353 } 354 else 355 { 356 for (int i = 0; i < args_length; ++i) 357 { 358 exp.args[i].compile (comp, Target.pushObject); 359 if (! code.reachableHere()) 360 break; 361 } 362 method = Compilation.applymethods[args_length]; 363 } 364 if (! code.reachableHere()) 365 { 366 comp.error('e', "unreachable code"); 367 return; 368 } 369 if (tail_recurse) 370 { 371 popParams(code, func_lambda, toArray); 372 code.emitTailCall(false, func_lambda.getVarScope()); 373 return; 374 } 375 code.emitInvokeVirtual(method); 376 target.compileFromStack(comp, Type.pointer_type); 377 } 378 379 protected Expression walk (ExpWalker walker) 380 { 381 return walker.walkApplyExp(this); 382 } 383 384 protected void walkChildren(ExpWalker walker) 385 { 386 func = walker.walk(func); 387 if (walker.exitValue == null) 388 args = walker.walkExps(args, args.length); 389 } 390 391 public void print (OutPort out) 392 { 393 out.startLogicalBlock("(Apply", ")", 2); 394 if (isTailCall()) 395 out.print (" [tailcall]"); 396 if (type != null && type != Type.pointer_type) 397 { 398 out.print(" => "); 399 out.print(type); 400 } 401 out.writeSpaceFill(); 402 printLineColumn(out); 403 func.print(out); 404 for (int i = 0; i < args.length; ++i) 405 { 406 out.writeSpaceLinear(); 407 args[i].print(out); 408 } 409 out.endLogicalBlock(")"); 410 } 411 412 413 private static void pushArgs (LambdaExp lexp, Expression[] args, Compilation comp) 414 { 415 Declaration param = lexp.firstDecl(); 416 int args_length = args.length; 417 for (int i = 0; i < args_length; ++i) 418 { 419 Expression arg = args[i]; 420 if (param.ignorable()) 421 arg.compile(comp, Target.Ignore); 422 else 423 arg.compile(comp, param.getType()); 424 param = param.nextDecl(); 425 } 426 } 427 428 private static void popParams (CodeAttr code, LambdaExp lexp, 429 boolean toArray) 430 { 431 Variable vars = lexp.getVarScope().firstVar(); 432 Declaration decls = lexp.firstDecl(); 433 if (vars != null && vars.getName() == "this") 434 vars = vars.nextVar(); 435 if (vars != null && vars.getName() == "$ctx") 436 vars = vars.nextVar(); 437 if (vars != null && vars.getName() == "argsArray") 438 { 439 if (toArray) 440 { 441 popParams (code, 1, decls, vars); 442 return; 443 } 444 vars = vars.nextVar(); 445 } 446 popParams (code, lexp.min_args, decls, vars); 447 } 448 449 private static void popParams (CodeAttr code, int count, 451 Declaration decl, Variable vars) 452 { 453 if (count > 0) 454 { 455 popParams (code, count - 1, decl.nextDecl(), 456 decl.getVariable() == null ? vars : vars.nextVar()); 457 if (! decl.ignorable()) 458 code.emitStore(vars); 459 } 460 } 461 462 463 protected Type type; 464 465 public final gnu.bytecode.Type getTypeRaw() 466 { 467 return type; 468 } 469 470 public final void setType (gnu.bytecode.Type type) 471 { 472 this.type = type; 473 } 474 475 public final gnu.bytecode.Type getType() 476 { 477 if (type != null) 478 return type; 479 Expression afunc = func; 480 type = Type.pointer_type; 482 if (afunc instanceof ReferenceExp) 483 { 484 Declaration func_decl = ((ReferenceExp) afunc).binding; 485 func_decl = Declaration.followAliases(func_decl); 486 if (func_decl != null && ! func_decl.getFlag(Declaration.IS_UNKNOWN)) 487 afunc = func_decl.getValue(); 488 } 489 if (afunc instanceof QuoteExp) 490 { 491 Object proc = ((QuoteExp) afunc).getValue(); 492 if (proc instanceof Inlineable) 493 type = ((Inlineable) proc).getReturnType(args); 494 } 495 else if (afunc instanceof LambdaExp) 496 { 497 type = ((LambdaExp) afunc).getReturnType(); 498 } 499 return type; 500 } 501 502 public final Expression inlineIfConstant(Procedure proc, ExpWalker walker) 503 { 504 return inlineIfConstant(proc, walker.getMessages()); 505 } 506 507 513 public final Expression inlineIfConstant(Procedure proc, SourceMessages messages) 514 { 515 int len = args.length; 516 Object [] vals = new Object [len]; 517 for (int i = len; --i >= 0; ) 518 { 519 Expression arg = args[i]; 520 if (arg instanceof ReferenceExp) 521 { 522 Declaration decl = ((ReferenceExp) arg).getBinding(); 523 if (decl != null) 524 { 525 arg = decl.getValue(); 526 if (arg == QuoteExp.undefined_exp) 527 return this; 528 } 529 } 530 if (! (arg instanceof QuoteExp)) 531 return this; 532 vals[i] = ((QuoteExp) arg).getValue(); 533 } 534 try 535 { 536 return new QuoteExp(proc.applyN(vals)); 537 } 538 catch (Throwable ex) 539 { 540 if (messages != null) 541 messages.error('w', "call to " + proc + 542 " throws " + ex); 543 return this; 544 } 545 } 546 547 public String toString () 548 { 549 return "ApplyExp/"+args.length+'['+func+']'; 550 } 551 } 552 | Popular Tags |