1/* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16/** 17 * Imlementation of bytecode generator. 18 * The PandaGen works with IR and provides an API 19 * to the compiler. 20 * 21 * This file should not contain imports of TypeScipt's AST nodes. 22 */ 23import * as ts from "typescript"; 24import { 25 BinaryOperator, 26 PrefixUnaryOperator, 27 SyntaxKind 28} from "typescript"; 29import { 30 call, 31 closeIterator, 32 copyDataProperties, 33 copyModuleIntoCurrentModule, 34 creatDebugger, 35 createArrayWithBuffer, 36 createEmptyArray, 37 createEmptyObject, 38 createObjectHavingMethod, 39 createObjectWithBuffer, 40 createObjectWithExcludedKeys, 41 createRegExpWithLiteral, 42 defineAsyncFunc, 43 defineClassWithBuffer, 44 defineFunc, 45 defineGeneratorFunc, 46 defineGetterSetterByValue, 47 defineMethod, 48 defineNCFunc, 49 deleteObjProperty, 50 getIterator, 51 getIteratorNext, 52 getNextPropName, 53 getPropIterator, 54 importModule, 55 isFalse, 56 isTrue, 57 jumpTarget, 58 ldSuperByName, 59 ldSuperByValue, 60 loadAccumulator, 61 loadAccumulatorFloat, 62 loadAccumulatorInt, 63 loadAccumulatorString, 64 loadGlobalVar, 65 loadHomeObject, 66 loadLexicalVar, 67 loadModuleVarByName, 68 loadObjByIndex, 69 loadObjByName, 70 loadObjByValue, 71 moveVreg, 72 newLexicalEnv, 73 newObject, 74 popLexicalEnv, 75 returnUndefined, 76 setObjectWithProto, 77 stClassToGlobalRecord, 78 stConstToGlobalRecord, 79 stLetToGlobalRecord, 80 storeAccumulator, 81 storeArraySpread, 82 storeGlobalVar, 83 storeLexicalVar, 84 storeModuleVariable, 85 storeObjByIndex, 86 storeObjByName, 87 storeObjByValue, 88 storeOwnByIndex, 89 storeOwnByName, 90 storeOwnByValue, 91 stSuperByName, 92 stSuperByValue, 93 superCall, 94 superCallSpread, 95 throwDeleteSuperProperty, 96 throwException, 97 throwIfNotObject, 98 throwIfSuperNotCorrectCall, 99 throwObjectNonCoercible, 100 throwThrowNotExists, 101 throwUndefinedIfHole, 102 tryLoadGlobalByName, 103 tryStoreGlobalByName, 104 loadAccumulatorBigInt 105} from "./base/bcGenUtil"; 106import { 107 Literal, 108 LiteralBuffer, 109 LiteralTag 110} from "./base/literal"; 111import { BaseType } from "./base/typeSystem"; 112import { getParamLengthOfFunc } from "./base/util"; 113import { 114 CacheList, 115 getVregisterCache, 116 VregisterCache 117} from "./base/vregisterCache"; 118import { CmdOptions } from "./cmdOptions"; 119import { 120 DebugInfo, 121 NodeKind, 122 VariableDebugInfo 123} from "./debuginfo"; 124import { isInteger } from "./expression/numericLiteral"; 125import { 126 EcmaAdd2dyn, 127 EcmaAnd2dyn, 128 EcmaAshr2dyn, 129 EcmaAsyncfunctionawaituncaught, 130 EcmaAsyncfunctionenter, 131 EcmaAsyncfunctionreject, 132 EcmaAsyncfunctionresolve, 133 EcmaCallspreaddyn, 134 EcmaCopyrestargs, 135 EcmaCreategeneratorobj, 136 EcmaCreateiterresultobj, 137 EcmaDecdyn, 138 EcmaDiv2dyn, 139 EcmaEqdyn, 140 EcmaExpdyn, 141 EcmaGetresumemode, 142 EcmaGettemplateobject, 143 EcmaGetunmappedargs, 144 EcmaGreaterdyn, 145 EcmaGreatereqdyn, 146 EcmaIncdyn, 147 EcmaInstanceofdyn, 148 EcmaIsindyn, 149 EcmaLessdyn, 150 EcmaLesseqdyn, 151 EcmaMod2dyn, 152 EcmaMul2dyn, 153 EcmaNegdyn, 154 EcmaNewobjspreaddyn, 155 EcmaNotdyn, 156 EcmaNoteqdyn, 157 EcmaOr2dyn, 158 EcmaResumegenerator, 159 EcmaShl2dyn, 160 EcmaShr2dyn, 161 EcmaStricteqdyn, 162 EcmaStrictnoteqdyn, 163 EcmaSub2dyn, 164 EcmaSuspendgenerator, 165 EcmaTonumber, 166 EcmaTypeofdyn, 167 EcmaXor2dyn, 168 Imm, 169 IRNode, 170 Jeqz, 171 Label, 172 ReturnDyn, 173 VReg 174} from "./irnodes"; 175import { 176 VariableAccessLoad, 177 VariableAcessStore 178} from "./lexenv"; 179import { LOGE } from "./log"; 180import { 181 FunctionScope, 182 LoopScope, 183 Scope, 184 VariableScope 185} from "./scope"; 186import { CatchTable } from "./statement/tryStatement"; 187import { TypeRecorder } from "./typeRecorder"; 188import { Variable } from "./variable"; 189 190export class PandaGen { 191 // @ts-ignore 192 private debugTag: string = "PandaGen"; 193 readonly internalName: string; 194 private parametersCount: number; 195 private locals: VReg[] = []; 196 private temps: VReg[] = []; 197 private insns: IRNode[] = []; 198 private scope: Scope | undefined; 199 private vregisterCache: VregisterCache; 200 private catchMap: Map<Label, CatchTable> = new Map<Label, CatchTable>(); 201 private totalRegsNum = 0; 202 // for debug info 203 private variableDebugInfoArray: VariableDebugInfo[] = []; 204 private firstStmt: ts.Statement | undefined; 205 private sourceFileDebugInfo: string = ""; 206 private sourceCodeDebugInfo: string | undefined; 207 private callType: number = 0; 208 209 private static literalArrayBuffer: Array<LiteralBuffer> = new Array<LiteralBuffer>(); 210 211 constructor(internalName: string, parametersCount: number, scope: Scope | undefined = undefined) { 212 this.internalName = internalName; 213 this.parametersCount = parametersCount; 214 this.scope = scope; 215 this.vregisterCache = new VregisterCache(); 216 } 217 218 public appendScopeInfo(lexVarInfo: Map<string, number>): number | undefined { 219 if (lexVarInfo.size == 0) { 220 return undefined; 221 } 222 223 let scopeInfoIdx: number | undefined = undefined; 224 scopeInfoIdx = PandaGen.getLiteralArrayBuffer().length; 225 let scopeInfo = new LiteralBuffer(); 226 let scopeInfoLiterals = new Array<Literal>(); 227 scopeInfoLiterals.push(new Literal(LiteralTag.INTEGER, lexVarInfo.size)); 228 lexVarInfo.forEach((slot: number, name: string) => { 229 scopeInfoLiterals.push(new Literal(LiteralTag.STRING, name)); 230 scopeInfoLiterals.push(new Literal(LiteralTag.INTEGER, slot)); 231 }); 232 scopeInfo.addLiterals(...scopeInfoLiterals); 233 PandaGen.getLiteralArrayBuffer().push(scopeInfo); 234 return scopeInfoIdx; 235 } 236 237 public setCallType(callType: number) { 238 this.callType = callType; 239 } 240 241 public getCallType(): number { 242 return this.callType; 243 } 244 245 static getExportedTypes() { 246 if (TypeRecorder.getInstance()) { 247 return TypeRecorder.getInstance().getExportedType(); 248 } else { 249 return new Map<string, number>(); 250 } 251 } 252 253 static getDeclaredTypes() { 254 if (TypeRecorder.getInstance()) { 255 return TypeRecorder.getInstance().getDeclaredType(); 256 } else { 257 return new Map<string, number>(); 258 } 259 } 260 261 public getSourceCodeDebugInfo() { 262 return this.sourceCodeDebugInfo; 263 } 264 265 public setSourceCodeDebugInfo(code: string) { 266 this.sourceCodeDebugInfo = code; 267 } 268 269 public getSourceFileDebugInfo() { 270 return this.sourceFileDebugInfo; 271 } 272 273 public setSourceFileDebugInfo(sourceFile: string) { 274 this.sourceFileDebugInfo = sourceFile; 275 } 276 277 static getLiteralArrayBuffer() { 278 return PandaGen.literalArrayBuffer; 279 } 280 281 static clearLiteralArrayBuffer() { 282 PandaGen.literalArrayBuffer = []; 283 } 284 285 getParameterLength() { 286 if (this.scope instanceof FunctionScope) { 287 return this.scope.getParameterLength(); 288 } 289 } 290 291 getFuncName() { 292 if (this.scope instanceof FunctionScope) { 293 return this.scope.getFuncName(); 294 } else { 295 return "main"; 296 } 297 } 298 299 static appendTypeArrayBuffer(type: BaseType): number { 300 let index = PandaGen.literalArrayBuffer.length; 301 PandaGen.literalArrayBuffer.push(type.transfer2LiteralBuffer()); 302 return index; 303 } 304 305 static setTypeArrayBuffer(type: BaseType, index: number) { 306 PandaGen.literalArrayBuffer[index] = type.transfer2LiteralBuffer(); 307 } 308 309 getFirstStmt() { 310 return this.firstStmt; 311 } 312 313 setFirstStmt(firstStmt: ts.Statement) { 314 if (this.firstStmt) { 315 return; 316 } 317 this.firstStmt = firstStmt; 318 } 319 320 getVregisterCache() { 321 return this.vregisterCache; 322 } 323 324 getCatchMap() { 325 return this.catchMap; 326 } 327 328 getScope(): Scope | undefined { 329 return this.scope; 330 } 331 332 getVariableDebugInfoArray(): VariableDebugInfo[] { 333 return this.variableDebugInfoArray; 334 } 335 336 addDebugVariableInfo(variable: VariableDebugInfo) { 337 this.variableDebugInfoArray.push(variable); 338 } 339 340 allocLocalVreg(): VReg { 341 let vreg = new VReg(); 342 this.locals.push(vreg); 343 return vreg; 344 } 345 346 getVregForVariable(v: Variable): VReg { 347 if (v.hasAlreadyBinded()) { 348 return v.getVreg(); 349 } 350 let vreg = this.allocLocalVreg(); 351 v.bindVreg(vreg); 352 return vreg; 353 } 354 355 getTemp(): VReg { 356 let retval: VReg; 357 if (this.temps.length > 0) { 358 retval = this.temps.shift()!; 359 } else { 360 retval = new VReg(); 361 } 362 363 return retval; 364 } 365 366 freeTemps(...temps: VReg[]) { 367 this.temps.unshift(...temps); 368 } 369 370 getInsns(): IRNode[] { 371 return this.insns; 372 } 373 374 setInsns(insns: IRNode[]) { 375 this.insns = insns; 376 } 377 378 printInsns() { 379 LOGE("function " + this.internalName + "() {"); 380 this.getInsns().forEach(ins => { 381 LOGE(ins.toString()); 382 }) 383 LOGE("}"); 384 } 385 386 setTotalRegsNum(num: number) { 387 this.totalRegsNum = num; 388 } 389 390 getTotalRegsNum(): number { 391 return this.totalRegsNum; 392 } 393 394 setParametersCount(count: number) { 395 this.parametersCount = count; 396 } 397 398 getParametersCount(): number { 399 return this.parametersCount; 400 } 401 402 setLocals(locals: VReg[]) { 403 this.locals = locals; 404 } 405 406 getLocals(): VReg[] { 407 return this.locals; 408 } 409 410 getTemps(): VReg[] { 411 return this.temps; 412 } 413 414 storeAccumulator(node: ts.Node | NodeKind, vreg: VReg) { 415 this.add(node, storeAccumulator(vreg)); 416 } 417 418 loadAccFromArgs(node: ts.Node) { 419 if ((<VariableScope>this.scope).getUseArgs()) { 420 let v = this.scope!.findLocal("arguments"); 421 if (this.scope instanceof FunctionScope) { 422 this.scope.setArgumentsOrRestargs(); 423 } 424 if (v) { 425 let paramVreg = this.getVregForVariable(v); 426 this.getUnmappedArgs(node); 427 this.add(node, storeAccumulator(paramVreg)); 428 } else { 429 throw new Error("fail to get arguments"); 430 } 431 } 432 } 433 434 deleteObjProperty(node: ts.Node, obj: VReg, prop: VReg) { 435 this.add(node, deleteObjProperty(obj, prop)); 436 } 437 438 loadAccumulator(node: ts.Node | NodeKind, vreg: VReg) { 439 this.add(node, loadAccumulator(vreg)); 440 } 441 442 createLexEnv(node: ts.Node, env: VReg, scope: VariableScope | LoopScope) { 443 let numVars = scope.getNumLexEnv(); 444 let scopeInfoIdx: number | undefined = undefined; 445 let lexVarInfo = scope.getLexVarInfo(); 446 if (CmdOptions.isDebugMode()) { 447 scopeInfoIdx = this.appendScopeInfo(lexVarInfo); 448 } 449 450 this.add( 451 node, 452 newLexicalEnv(numVars, scopeInfoIdx), 453 storeAccumulator(env) 454 ) 455 } 456 457 popLexicalEnv(node: ts.Node) { 458 this.add( 459 node, 460 popLexicalEnv() 461 ) 462 } 463 464 loadAccFromLexEnv(node: ts.Node, scope: Scope, level: number, v: Variable) { 465 let expander = new VariableAccessLoad(scope, level, v); 466 let insns = expander.expand(this); 467 this.add( 468 node, 469 ...insns 470 ); 471 } 472 473 storeAccToLexEnv(node: ts.Node | NodeKind, scope: Scope, level: number, v: Variable, isDeclaration: boolean) { 474 let expander = new VariableAcessStore(scope, level, v, isDeclaration, node); 475 let insns = expander.expand(this); 476 this.add( 477 node, 478 ...insns 479 ) 480 } 481 482 loadObjProperty(node: ts.Node, obj: VReg, prop: VReg | string | number) { 483 switch (typeof (prop)) { 484 case "number": { 485 if (isInteger(prop)) { 486 this.loadObjByIndex(node, obj, prop); 487 } else { 488 let propReg = this.getTemp(); 489 this.add( 490 node, 491 loadAccumulatorFloat(prop), 492 storeAccumulator(propReg), 493 ); 494 this.loadObjByValue(node, obj, propReg); 495 this.freeTemps(propReg); 496 } 497 break; 498 } 499 case "string": 500 this.loadObjByName(node, obj, prop); 501 break; 502 default: 503 this.loadObjByValue(node, obj, prop); 504 } 505 } 506 507 storeObjProperty(node: ts.Node | NodeKind, obj: VReg, prop: VReg | string | number) { 508 switch (typeof (prop)) { 509 case "number": 510 if (isInteger(prop)) { 511 this.storeObjByIndex(node, obj, prop); 512 } else { 513 let valueReg = this.getTemp(); 514 let propReg = this.getTemp(); 515 this.storeAccumulator(node, valueReg); 516 this.add( 517 node, 518 loadAccumulatorFloat(prop), 519 storeAccumulator(propReg), 520 loadAccumulator(valueReg) 521 ); 522 this.storeObjByValue(node, obj, propReg); 523 this.freeTemps(valueReg, propReg); 524 } 525 break; 526 case "string": 527 this.storeObjByName(node, obj, prop); 528 break; 529 default: 530 this.storeObjByValue(node, obj, prop); 531 } 532 } 533 534 storeOwnProperty(node: ts.Node | NodeKind, obj: VReg, prop: VReg | string | number, nameSetting: boolean = false) { 535 switch (typeof prop) { 536 case "number": { 537 if (isInteger(prop)) { 538 this.stOwnByIndex(node, obj, prop); 539 } else { 540 let valueReg = this.getTemp(); 541 let propReg = this.getTemp(); 542 this.storeAccumulator(node, valueReg); 543 this.add( 544 node, 545 loadAccumulatorFloat(prop), 546 storeAccumulator(propReg), 547 loadAccumulator(valueReg) 548 ); 549 this.stOwnByValue(node, obj, propReg, nameSetting); 550 this.freeTemps(valueReg, propReg); 551 } 552 break; 553 } 554 case "string": 555 this.stOwnByName(node, obj, prop, nameSetting); 556 break; 557 default: 558 this.stOwnByValue(node, obj, prop, nameSetting); 559 } 560 } 561 562 private loadObjByName(node: ts.Node, obj: VReg, string_id: string) { 563 this.add( 564 node, 565 loadObjByName(obj, string_id) 566 ); 567 } 568 569 private storeObjByName(node: ts.Node | NodeKind, obj: VReg, string_id: string) { 570 this.add( 571 node, 572 storeObjByName(obj, string_id) 573 ); 574 } 575 576 private loadObjByIndex(node: ts.Node, obj: VReg, index: number) { 577 this.add( 578 node, 579 loadObjByIndex(obj, index) 580 ) 581 } 582 583 private storeObjByIndex(node: ts.Node | NodeKind, obj: VReg, index: number) { 584 this.add( 585 node, 586 storeObjByIndex(obj, index) 587 ) 588 } 589 590 591 private loadObjByValue(node: ts.Node, obj: VReg, value: VReg) { 592 this.add( 593 node, 594 loadObjByValue(obj, value) 595 ) 596 } 597 598 private storeObjByValue(node: ts.Node | NodeKind, obj: VReg, prop: VReg) { 599 this.add( 600 node, 601 storeObjByValue(obj, prop) 602 ) 603 } 604 605 private stOwnByName(node: ts.Node | NodeKind, obj: VReg, string_id: string, nameSetting: boolean) { 606 this.add(node, storeOwnByName(obj, string_id, nameSetting)); 607 } 608 609 private stOwnByIndex(node: ts.Node | NodeKind, obj: VReg, index: number) { 610 this.add(node, storeOwnByIndex(obj, index)); 611 } 612 613 private stOwnByValue(node: ts.Node | NodeKind, obj: VReg, value: VReg, nameSetting: boolean) { 614 this.add(node, storeOwnByValue(obj, value, nameSetting)); 615 } 616 617 loadByNameViaDebugger(node: ts.Node, string_id: string, boolVal: CacheList) { 618 this.loadObjProperty(node, getVregisterCache(this, CacheList.Global), "debuggerGetValue"); 619 let getValueReg = this.getTemp(); 620 this.storeAccumulator(node, getValueReg); 621 let variableReg = this.getTemp(); 622 this.loadAccumulatorString(node, string_id); 623 this.storeAccumulator(node, variableReg); 624 let trueValueReg = this.getTemp(); 625 this.moveVreg(node, trueValueReg, getVregisterCache(this, boolVal)); 626 this.call(node, [getValueReg, variableReg, trueValueReg], false); 627 this.freeTemps(getValueReg, variableReg, trueValueReg); 628 } 629 630 // eg. print 631 tryLoadGlobalByName(node: ts.Node, string_id: string) { 632 CmdOptions.isWatchEvaluateExpressionMode() ? this.loadByNameViaDebugger(node, string_id, CacheList.True) 633 : this.add(node, tryLoadGlobalByName(string_id)); 634 } 635 636 storeByNameViaDebugger(node: ts.Node, string_id: string) { 637 let valueReg = this.getTemp(); 638 this.storeAccumulator(node, valueReg); 639 this.loadObjProperty(node, getVregisterCache(this, CacheList.Global), "debuggerSetValue"); 640 let setValueReg = this.getTemp(); 641 this.storeAccumulator(node, setValueReg); 642 let variableReg = this.getTemp(); 643 this.loadAccumulatorString(node, string_id); 644 this.storeAccumulator(node, variableReg); 645 this.call(node, [setValueReg, variableReg, valueReg], false); 646 this.freeTemps(valueReg, setValueReg, variableReg); 647 } 648 649 // eg. a = 1 650 tryStoreGlobalByName(node: ts.Node, string_id: string) { 651 CmdOptions.isWatchEvaluateExpressionMode() ? this.storeByNameViaDebugger(node, string_id) 652 : this.add(node, tryStoreGlobalByName(string_id)); 653 } 654 655 // eg. var n; n; 656 loadGlobalVar(node: ts.Node, string_id: string) { 657 this.add( 658 node, 659 loadGlobalVar(string_id)); 660 } 661 662 // var n = 1; 663 storeGlobalVar(node: ts.Node | NodeKind, string_id: string) { 664 this.add( 665 node, 666 storeGlobalVar(string_id)); 667 } 668 669 loadAccumulatorString(node: ts.Node | NodeKind, str: string) { 670 this.add(node, loadAccumulatorString(str)); 671 } 672 673 loadAccumulatorFloat(node: ts.Node, num: number) { 674 this.add(node, loadAccumulatorFloat(num)); 675 } 676 677 loadAccumulatorInt(node: ts.Node, num: number) { 678 this.add(node, loadAccumulatorInt(num)); 679 } 680 681 moveVreg(node: ts.Node | NodeKind, vd: VReg, vs: VReg) { 682 this.add(node, moveVreg(vd, vs)); 683 } 684 685 // @ts-ignore 686 label(node: ts.Node, label: Label) { 687 this.add(NodeKind.Invalid, label); 688 } 689 690 branch(node: ts.Node | NodeKind, target: Label) { 691 this.add(node, jumpTarget(target)); 692 } 693 694 isTrue(node: ts.Node) { 695 this.add( 696 node, 697 isTrue() 698 ) 699 } 700 701 jumpIfTrue(node: ts.Node, target: Label) { 702 this.isFalse(node); 703 this.add( 704 node, 705 new Jeqz(target) 706 ) 707 } 708 709 isFalse(node: ts.Node) { 710 this.add( 711 node, 712 isFalse() 713 ) 714 } 715 716 jumpIfFalse(node: ts.Node, target: Label) { 717 this.isTrue(node); 718 this.add( 719 node, 720 new Jeqz(target) 721 ) 722 } 723 724 debugger(node: ts.Node) { 725 this.add(node, creatDebugger()); 726 } 727 728 throwUndefinedIfHole(node: ts.Node, hole: VReg, name: VReg) { 729 this.add( 730 node, 731 throwUndefinedIfHole(hole, name) 732 ) 733 } 734 735 /** 736 * The method generates code for ther following cases 737 * if (lhs OP acc) {...} 738 * ifFalse: ... 739 */ 740 condition(node: ts.Node, op: SyntaxKind, lhs: VReg, ifFalse: Label) { 741 // Please keep order of cases the same as in types.ts 742 switch (op) { 743 case SyntaxKind.LessThanToken: // line 57 744 this.add(node, new EcmaLessdyn(lhs)); 745 this.add(node, new Jeqz(ifFalse)); 746 break; 747 case SyntaxKind.GreaterThanToken: // line 59 748 this.add(node, new EcmaGreaterdyn(lhs)); 749 this.add(node, new Jeqz(ifFalse)); 750 break; 751 case SyntaxKind.LessThanEqualsToken: // line 60 752 this.add(node, new EcmaLesseqdyn(lhs)); 753 this.add(node, new Jeqz(ifFalse)); 754 break; 755 case SyntaxKind.GreaterThanEqualsToken: // line 61 756 this.add(node, new EcmaGreatereqdyn(lhs)); 757 this.add(node, new Jeqz(ifFalse)); 758 break; 759 case SyntaxKind.EqualsEqualsToken: // line 62 760 this.add(node, new EcmaEqdyn(lhs)); 761 this.add(node, new Jeqz(ifFalse)); 762 break; 763 case SyntaxKind.ExclamationEqualsToken: // line 63 764 this.add(node, new EcmaNoteqdyn(lhs)); 765 this.add(node, new Jeqz(ifFalse)); 766 break; 767 case SyntaxKind.EqualsEqualsEqualsToken: // line 64 768 this.add(node, new EcmaStricteqdyn(lhs)); 769 this.add(node, new Jeqz(ifFalse)); 770 break; 771 case SyntaxKind.ExclamationEqualsEqualsToken: // line 65 772 this.add(node, new EcmaStrictnoteqdyn(lhs)); 773 this.add(node, new Jeqz(ifFalse)); 774 break; 775 default: 776 break; 777 } 778 } 779 780 unary(node: ts.Node, op: PrefixUnaryOperator, operand: VReg) { 781 switch (op) { 782 case SyntaxKind.PlusToken: 783 this.add(node, new EcmaTonumber(operand)); 784 break; 785 case SyntaxKind.MinusToken: 786 this.add(node, new EcmaNegdyn(operand)); 787 break; 788 case SyntaxKind.PlusPlusToken: 789 this.add(node, new EcmaIncdyn(operand)); 790 break; 791 case SyntaxKind.MinusMinusToken: 792 this.add(node, new EcmaDecdyn(operand)); 793 break; 794 case SyntaxKind.ExclamationToken: 795 let falseLabel = new Label(); 796 let endLabel = new Label(); 797 this.jumpIfFalse(node, falseLabel); 798 // operand is true 799 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.False))); 800 this.branch(node, endLabel); 801 // operand is false 802 this.label(node, falseLabel); 803 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.True))); 804 this.label(node, endLabel); 805 break; 806 case SyntaxKind.TildeToken: 807 this.add(node, new EcmaNotdyn(operand)); 808 break; 809 default: 810 throw new Error("Unimplemented"); 811 } 812 } 813 814 binary(node: ts.Node, op: BinaryOperator, lhs: VReg) { 815 switch (op) { 816 case SyntaxKind.LessThanToken: // line 57 817 case SyntaxKind.GreaterThanToken: // line 59 818 case SyntaxKind.LessThanEqualsToken: // line 60 819 case SyntaxKind.GreaterThanEqualsToken: // line 61 820 case SyntaxKind.EqualsEqualsToken: // line 62 821 case SyntaxKind.ExclamationEqualsToken: // line 63 822 case SyntaxKind.EqualsEqualsEqualsToken: // line 64 823 case SyntaxKind.ExclamationEqualsEqualsToken: // line 65 824 this.binaryRelation(node, op, lhs); 825 break; 826 case SyntaxKind.PlusToken: // line 67 827 case SyntaxKind.PlusEqualsToken: // line 91 828 this.add(node, new EcmaAdd2dyn(lhs)); 829 break; 830 case SyntaxKind.MinusToken: // line 68 831 case SyntaxKind.MinusEqualsToken: // line 92 832 this.add(node, new EcmaSub2dyn(lhs)); 833 break; 834 case SyntaxKind.AsteriskToken: // line 69 835 case SyntaxKind.AsteriskEqualsToken: // line 93 836 this.add(node, new EcmaMul2dyn(lhs)); 837 break; 838 case SyntaxKind.AsteriskAsteriskToken: // line 70 839 case SyntaxKind.AsteriskAsteriskEqualsToken: // line 94 840 this.add(node, new EcmaExpdyn(lhs)); 841 break; 842 case SyntaxKind.SlashToken: // line 71 843 case SyntaxKind.SlashEqualsToken: // line 95 844 this.add(node, new EcmaDiv2dyn(lhs)); 845 break; 846 case SyntaxKind.PercentToken: // line 72 847 case SyntaxKind.PercentEqualsToken: // line 96 848 this.add(node, new EcmaMod2dyn(lhs)); 849 break; 850 case SyntaxKind.LessThanLessThanToken: // line 75 851 case SyntaxKind.LessThanLessThanEqualsToken: // line 97 852 this.add(node, new EcmaShl2dyn(lhs)); 853 break; 854 case SyntaxKind.GreaterThanGreaterThanToken: // line 76 855 case SyntaxKind.GreaterThanGreaterThanEqualsToken: // line 98 856 this.add(node, new EcmaShr2dyn(lhs)); 857 break; 858 case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: // line 77 859 case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: // line 99 860 this.add(node, new EcmaAshr2dyn(lhs)); 861 break; 862 case SyntaxKind.AmpersandToken: // line 78 863 case SyntaxKind.AmpersandEqualsToken: // line 100 864 this.add(node, new EcmaAnd2dyn(lhs)); 865 break; 866 case SyntaxKind.BarToken: // line 79 867 case SyntaxKind.BarEqualsToken: // line 101 868 this.add(node, new EcmaOr2dyn(lhs)); 869 break; 870 case SyntaxKind.CaretToken: // line 80 871 case SyntaxKind.CaretEqualsToken: // line 102 872 this.add(node, new EcmaXor2dyn(lhs)); 873 break; 874 case SyntaxKind.InKeyword: //line 125 875 // The in operator returns true if the specified property is in the specified object or its prototype chain 876 this.add(node, new EcmaIsindyn(lhs)); 877 break; 878 case SyntaxKind.InstanceOfKeyword: //line 126 879 // The instanceof operator tests to see if the prototype property of 880 // a constructor appears anywhere in the prototype chain of an object. 881 // The return value is a boolean value. 882 this.add(node, new EcmaInstanceofdyn(lhs)); 883 break; 884 default: 885 throw new Error("Unimplemented"); 886 } 887 } 888 889 // throw needs argument of exceptionVreg 890 // to ensure rethrow the exception after finally 891 throw(node: ts.Node) { 892 this.add( 893 node, 894 throwException() 895 ); 896 } 897 898 throwThrowNotExist(node: ts.Node) { 899 this.add(node, throwThrowNotExists()); 900 } 901 902 throwDeleteSuperProperty(node: ts.Node) { 903 this.add(node, throwDeleteSuperProperty()); 904 } 905 906 return(node: ts.Node | NodeKind) { 907 this.add(node, new ReturnDyn()); 908 } 909 910 call(node: ts.Node, args: VReg[], passThis: boolean) { 911 this.add( 912 node, 913 call(args, passThis) 914 ) 915 } 916 917 returnUndefined(node: ts.Node | NodeKind) { 918 this.add( 919 node, 920 returnUndefined() 921 ) 922 } 923 924 newObject(node: ts.Node, args: VReg[]) { 925 this.add( 926 node, 927 newObject(args) 928 ); 929 } 930 931 defineMethod(node: ts.FunctionLikeDeclaration, name: string, objReg: VReg, env: VReg) { 932 let paramLength = getParamLengthOfFunc(node); 933 this.add( 934 node, 935 loadAccumulator(objReg), 936 defineMethod(name, env, paramLength) 937 ); 938 } 939 940 defineFunction(node: ts.FunctionLikeDeclaration | NodeKind, realNode: ts.FunctionLikeDeclaration, name: string, env: VReg) { 941 let paramLength = getParamLengthOfFunc(realNode); 942 if (realNode.modifiers) { 943 for (let i = 0; i < realNode.modifiers.length; i++) { 944 if (realNode.modifiers[i].kind == ts.SyntaxKind.AsyncKeyword) { 945 if (realNode.asteriskToken) { 946 // support async* further 947 } else { // async 948 this.add( 949 node, 950 defineAsyncFunc(name, env, paramLength) 951 ); 952 return; 953 } 954 } 955 } 956 } 957 958 if (realNode.asteriskToken) { 959 this.add( 960 node, 961 defineGeneratorFunc(name, env, paramLength) 962 ); 963 return; 964 } 965 966 if (ts.isArrowFunction(realNode) || ts.isMethodDeclaration(realNode)) { 967 this.add( 968 node, 969 loadHomeObject(), 970 defineNCFunc(name, env, paramLength) 971 ); 972 return; 973 } 974 975 this.add( 976 node, 977 defineFunc(name, env, paramLength) 978 ); 979 } 980 981 typeOf(node: ts.Node) { 982 this.add(node, new EcmaTypeofdyn()); 983 } 984 985 callSpread(node: ts.Node, func: VReg, thisReg: VReg, args: VReg) { 986 this.add(node, new EcmaCallspreaddyn(func, thisReg, args)); 987 } 988 989 newObjSpread(node: ts.Node, obj: VReg, target: VReg) { 990 this.add(node, new EcmaNewobjspreaddyn(obj, target)); 991 } 992 993 getUnmappedArgs(node: ts.Node) { 994 this.add(node, new EcmaGetunmappedargs()); 995 } 996 997 toNumber(node: ts.Node, arg: VReg) { 998 this.add(node, new EcmaTonumber(arg)); 999 } 1000 1001 createGeneratorObj(node: ts.Node, funcObj: VReg) { 1002 this.add(node, new EcmaCreategeneratorobj(funcObj)); 1003 } 1004 1005 EcmaCreateiterresultobj(node: ts.Node, value: VReg, done: VReg) { 1006 this.add(node, new EcmaCreateiterresultobj(value, done)); 1007 } 1008 1009 suspendGenerator(node: ts.Node, genObj: VReg, iterRslt: VReg) { 1010 this.add(node, new EcmaSuspendgenerator(genObj, iterRslt)); 1011 } 1012 1013 resumeGenerator(node: ts.Node, genObj: VReg) { 1014 this.add(node, new EcmaResumegenerator(genObj)); 1015 } 1016 1017 getResumeMode(node: ts.Node, genObj: VReg) { 1018 this.add(node, new EcmaGetresumemode(genObj)); 1019 } 1020 1021 asyncFunctionEnter(node: ts.Node | NodeKind) { 1022 this.add(node, new EcmaAsyncfunctionenter()); 1023 } 1024 1025 asyncFunctionAwaitUncaught(node: ts.Node, asynFuncObj: VReg, value: VReg) { 1026 this.add(node, new EcmaAsyncfunctionawaituncaught(asynFuncObj, value)); 1027 } 1028 1029 asyncFunctionResolve(node: ts.Node | NodeKind, asyncObj: VReg, value: VReg, canSuspend: VReg) { 1030 this.add(node, new EcmaAsyncfunctionresolve(asyncObj, value, canSuspend)); 1031 } 1032 1033 asyncFunctionReject(node: ts.Node | NodeKind, asyncObj: VReg, value: VReg, canSuspend: VReg) { 1034 this.add(node, new EcmaAsyncfunctionreject(asyncObj, value, canSuspend)); 1035 } 1036 1037 getTemplateObject(node: ts.Node | NodeKind, value: VReg) { 1038 this.add(node, new EcmaGettemplateobject(value)); 1039 } 1040 1041 copyRestArgs(node: ts.Node, index: number) { 1042 this.add(node, new EcmaCopyrestargs(new Imm(index))); 1043 } 1044 1045 getPropIterator(node: ts.Node) { 1046 this.add(node, getPropIterator()); 1047 } 1048 1049 getNextPropName(node: ts.Node, iter: VReg) { 1050 this.add(node, getNextPropName(iter)); 1051 } 1052 1053 createEmptyObject(node: ts.Node) { 1054 this.add(node, createEmptyObject()); 1055 } 1056 1057 createObjectHavingMethod(node: ts.Node, idx: number, env: VReg) { 1058 this.add( 1059 node, 1060 loadAccumulator(env), 1061 createObjectHavingMethod(idx) 1062 ); 1063 } 1064 1065 createObjectWithBuffer(node: ts.Node, idx: number) { 1066 this.add(node, createObjectWithBuffer(idx)); 1067 } 1068 1069 setObjectWithProto(node: ts.Node, proto: VReg, object: VReg) { 1070 this.add(node, setObjectWithProto(proto, object)); 1071 } 1072 1073 copyDataProperties(node: ts.Node, dstObj: VReg, srcObj: VReg) { 1074 this.add(node, copyDataProperties(dstObj, srcObj)); 1075 } 1076 1077 defineGetterSetterByValue(node: ts.Node, obj: VReg, name: VReg, getter: VReg, setter: VReg, isComputedPropertyName: boolean) { 1078 if (isComputedPropertyName) { 1079 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.True))); 1080 } else { 1081 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.False))); 1082 } 1083 this.add(node, defineGetterSetterByValue(obj, name, getter, setter)); 1084 } 1085 1086 createEmptyArray(node: ts.Node) { 1087 this.add(node, createEmptyArray()); 1088 } 1089 1090 createArrayWithBuffer(node: ts.Node, idx: number) { 1091 this.add(node, createArrayWithBuffer(idx)); 1092 } 1093 1094 storeArraySpreadElement(node: ts.Node, array: VReg, index: VReg) { 1095 this.add(node, storeArraySpread(array, index)); 1096 } 1097 1098 storeLexicalVar(node: ts.Node, level: number, slot: number, value: VReg) { 1099 this.add( 1100 node, 1101 storeLexicalVar(level, slot, value) 1102 ); 1103 } 1104 1105 loadLexicalVar(node: ts.Node, level: number, slot: number) { 1106 this.add( 1107 node, 1108 loadLexicalVar(level, slot) 1109 ) 1110 } 1111 1112 importModule(node: ts.Node, moduleName: string) { 1113 this.add(node, importModule(moduleName)); 1114 } 1115 1116 loadModuleVariable(node: ts.Node, module: VReg, varName: string) { 1117 this.add(node, loadModuleVarByName(varName, module)); 1118 } 1119 1120 storeModuleVar(node: ts.Node, moduleVarName: string) { 1121 this.add(node, storeModuleVariable(moduleVarName)); 1122 } 1123 1124 copyModule(node: ts.Node, module: VReg) { 1125 this.add(node, copyModuleIntoCurrentModule(module)); 1126 } 1127 1128 defineClassWithBuffer(node: ts.Node, name: string, idx: number, parameterLength: number, base: VReg) { 1129 this.add( 1130 node, 1131 defineClassWithBuffer(name, idx, parameterLength, getVregisterCache(this, CacheList.LexEnv), base) 1132 ) 1133 } 1134 1135 createObjectWithExcludedKeys(node: ts.Node, obj: VReg, args: VReg[]) { 1136 this.add( 1137 node, 1138 createObjectWithExcludedKeys(obj, args) 1139 ); 1140 } 1141 1142 throwObjectNonCoercible(node: ts.Node) { 1143 this.add( 1144 node, 1145 throwObjectNonCoercible() 1146 ); 1147 } 1148 1149 getIterator(node: ts.Node) { 1150 this.add( 1151 node, 1152 getIterator() 1153 ); 1154 } 1155 1156 getIteratorNext(node: ts.Node, iter: VReg, nextMethod: VReg) { 1157 this.add( 1158 node, 1159 getIteratorNext(iter, nextMethod) 1160 ) 1161 } 1162 1163 closeIterator(node: ts.Node, iter: VReg) { 1164 this.add( 1165 node, 1166 closeIterator(iter) 1167 ) 1168 } 1169 1170 throwIfNotObject(node: ts.Node, obj: VReg) { 1171 this.add( 1172 node, 1173 throwIfNotObject(obj) 1174 ); 1175 } 1176 1177 superCall(node: ts.Node, num: number, start: VReg) { 1178 this.add( 1179 node, 1180 superCall(num, start) 1181 ) 1182 } 1183 1184 superCallSpread(node: ts.Node, vs: VReg) { 1185 this.add(node, superCallSpread(vs)); 1186 } 1187 1188 ldSuperByName(node: ts.Node, obj: VReg, key: string) { 1189 this.add( 1190 node, 1191 ldSuperByName(obj, key) 1192 ) 1193 } 1194 1195 stSuperByName(node: ts.Node, obj: VReg, key: string) { 1196 this.add( 1197 node, 1198 stSuperByName(obj, key) 1199 ) 1200 } 1201 1202 ldSuperByValue(node: ts.Node, obj: VReg, prop: VReg) { 1203 this.add( 1204 node, 1205 ldSuperByValue(obj, prop) 1206 ) 1207 } 1208 1209 stSuperByValue(node: ts.Node, obj: VReg, prop: VReg) { 1210 this.add( 1211 node, 1212 stSuperByValue(obj, prop) 1213 ) 1214 } 1215 1216 loadSuperProperty(node: ts.Node, obj: VReg, prop: VReg | string | number) { 1217 switch (typeof (prop)) { 1218 case "string": 1219 this.ldSuperByName(node, obj, prop); 1220 break; 1221 case "number": 1222 let propReg = this.getTemp(); 1223 this.loadAccumulatorInt(node, prop); 1224 this.storeAccumulator(node, propReg); 1225 this.ldSuperByValue(node, obj, propReg); 1226 this.freeTemps(propReg) 1227 break; 1228 default: 1229 this.ldSuperByValue(node, obj, prop); 1230 } 1231 } 1232 1233 throwIfSuperNotCorrectCall(node: ts.Node, num: number) { 1234 this.add(node, throwIfSuperNotCorrectCall(num)); 1235 } 1236 1237 storeSuperProperty(node: ts.Node, obj: VReg, prop: VReg | string | number) { 1238 switch (typeof (prop)) { 1239 case "string": 1240 this.stSuperByName(node, obj, prop); 1241 break; 1242 case "number": 1243 let propReg = this.getTemp(); 1244 this.loadAccumulatorInt(node, prop); 1245 this.storeAccumulator(node, propReg); 1246 this.stSuperByValue(node, obj, propReg); 1247 this.freeTemps(propReg) 1248 break; 1249 default: 1250 this.stSuperByValue(node, obj, prop); 1251 } 1252 } 1253 1254 loadHomeObject(node: ts.Node) { 1255 this.add( 1256 node, 1257 loadHomeObject() 1258 ) 1259 } 1260 1261 createRegExpWithLiteral(node: ts.Node, pattern: string, flags: number) { 1262 this.add( 1263 node, 1264 createRegExpWithLiteral(pattern, flags) 1265 ) 1266 } 1267 1268 stLetToGlobalRecord(node: ts.Node, string_id: string) { 1269 this.add( 1270 node, 1271 stLetToGlobalRecord(string_id)); 1272 } 1273 1274 stConstToGlobalRecord(node: ts.Node, string_id: string) { 1275 this.add( 1276 node, 1277 stConstToGlobalRecord(string_id)); 1278 } 1279 1280 stClassToGlobalRecord(node: ts.Node, string_id: string) { 1281 this.add( 1282 node, 1283 stClassToGlobalRecord(string_id)); 1284 } 1285 1286 loadAccumulatorBigInt(node: ts.Node | NodeKind, str: string) { 1287 this.add( 1288 node, 1289 loadAccumulatorBigInt(str)); 1290 } 1291 1292 private binaryRelation(node: ts.Node, op: BinaryOperator, lhs: VReg) { 1293 let falseLabel = new Label(); 1294 let endLabel = new Label(); 1295 switch (op) { 1296 case SyntaxKind.LessThanToken: 1297 this.add(node, new EcmaLessdyn(lhs)); 1298 break; 1299 case SyntaxKind.GreaterThanToken: 1300 this.add(node, new EcmaGreaterdyn(lhs)); 1301 break; 1302 case SyntaxKind.LessThanEqualsToken: 1303 this.add(node, new EcmaLesseqdyn(lhs)); 1304 break; 1305 case SyntaxKind.GreaterThanEqualsToken: 1306 this.add(node, new EcmaGreatereqdyn(lhs)); 1307 break; 1308 case SyntaxKind.EqualsEqualsToken: 1309 this.add(node, new EcmaEqdyn(lhs)); 1310 break; 1311 case SyntaxKind.ExclamationEqualsToken: 1312 this.add(node, new EcmaNoteqdyn(lhs)); 1313 break; 1314 case SyntaxKind.EqualsEqualsEqualsToken: 1315 this.add(node, new EcmaStricteqdyn(lhs)); 1316 break; 1317 case SyntaxKind.ExclamationEqualsEqualsToken: 1318 this.add(node, new EcmaStrictnoteqdyn(lhs)); 1319 break; 1320 default: 1321 break; 1322 } 1323 this.add(node, new Jeqz(falseLabel)); 1324 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.True))); 1325 this.branch(node, endLabel); 1326 this.label(node, falseLabel); 1327 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.False))); 1328 this.label(node, endLabel); 1329 } 1330 1331 private add(node: ts.Node | NodeKind, ...insns: IRNode[]): void { 1332 // set pos debug info if debug mode 1333 DebugInfo.setDebuginfoForIns(node, ...insns); 1334 1335 this.insns.push(...insns); 1336 } 1337} 1338