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 * Implementation 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 creatDebugger, 34 createArrayWithBuffer, 35 createEmptyArray, 36 createEmptyObject, 37 createObjectWithBuffer, 38 createObjectWithExcludedKeys, 39 createRegExpWithLiteral, 40 defineClassWithBuffer, 41 defineFunc, 42 defineGetterSetterByValue, 43 defineMethod, 44 deleteObjProperty, 45 dynamicImport, 46 getIterator, 47 getNextPropName, 48 getPropIterator, 49 getModuleNamespace, 50 isFalse, 51 isTrue, 52 jumpTarget, 53 ldSuperByName, 54 ldSuperByValue, 55 loadAccumulator, 56 loadAccumulatorFloat, 57 loadAccumulatorInt, 58 loadAccumulatorString, 59 loadExternalModuleVariable, 60 loadGlobalVar, 61 loadLexicalVar, 62 loadLocalModuleVariable, 63 loadObjByIndex, 64 loadObjByName, 65 loadObjByValue, 66 moveVreg, 67 newLexicalEnv, 68 newObject, 69 popLexicalEnv, 70 returnUndefined, 71 setObjectWithProto, 72 stConstToGlobalRecord, 73 stLetOrClassToGlobalRecord, 74 storeAccumulator, 75 storeArraySpread, 76 storeGlobalVar, 77 storeLexicalVar, 78 storeModuleVariable, 79 storeObjByIndex, 80 storeObjByName, 81 storeObjByValue, 82 storeOwnByIndex, 83 storeOwnByName, 84 storeOwnByValue, 85 stSuperByName, 86 stSuperByValue, 87 superCall, 88 superCallInArrow, 89 superCallSpread, 90 throwConstAssignment, 91 throwDeleteSuperProperty, 92 throwException, 93 throwIfNotObject, 94 throwIfSuperNotCorrectCall, 95 throwObjectNonCoercible, 96 throwThrowNotExists, 97 throwUndefinedIfHole, 98 tryLoadGlobalByName, 99 tryStoreGlobalByName, 100 loadAccumulatorBigInt 101} from "./base/bcGenUtil"; 102import { 103 Literal, 104 LiteralBuffer, 105 LiteralTag 106} from "./base/literal"; 107import { BaseType } from "./base/typeSystem"; 108import { getParamLengthOfFunc, MAX_INT8 } from "./base/util"; 109import { 110 CacheList, 111 getVregisterCache, 112 VregisterCache 113} from "./base/vregisterCache"; 114import { CmdOptions } from "./cmdOptions"; 115import { 116 DebugInfo, 117 NodeKind, 118 VariableDebugInfo 119} from "./debuginfo"; 120import { isInteger } from "./expression/numericLiteral"; 121import { 122 Asyncgeneratorreject, 123 Add2, 124 And2, 125 Ashr2, 126 Asyncfunctionawaituncaught, 127 Asyncfunctionenter, 128 Asyncfunctionreject, 129 Asyncfunctionresolve, 130 Apply, 131 Copyrestargs, 132 WideCopyrestargs, 133 Creategeneratorobj, 134 Createasyncgeneratorobj, 135 Createiterresultobj, 136 Asyncgeneratorresolve, 137 Dec, 138 Div2, 139 Eq, 140 Exp, 141 Getasynciterator, 142 Getresumemode, 143 Gettemplateobject, 144 Getunmappedargs, 145 Greater, 146 Greatereq, 147 Inc, 148 Instanceof, 149 Isin, 150 Less, 151 Lesseq, 152 Mod2, 153 Mul2, 154 Neg, 155 Newobjapply, 156 Not, 157 Noteq, 158 Or2, 159 Resumegenerator, 160 Setgeneratorstate, 161 Shl2, 162 Shr2, 163 Stricteq, 164 Strictnoteq, 165 Sub2, 166 Suspendgenerator, 167 Tonumber, 168 Tonumeric, 169 Typeof, 170 Xor2, 171 Imm, 172 IRNode, 173 Jeqz, 174 Label, 175 Return, 176 VReg 177} from "./irnodes"; 178import { 179 VariableAccessLoad, 180 VariableAcessStore 181} from "./lexenv"; 182import { LOGE } from "./log"; 183import { 184 FunctionScope, 185 LoopScope, 186 Scope, 187 VariableScope 188} from "./scope"; 189import { CatchTable } from "./statement/tryStatement"; 190import { TypeRecorder } from "./typeRecorder"; 191import { 192 MandatoryArguments, 193 ModuleVariable, 194 Variable 195} from "./variable"; 196import * as jshelpers from "./jshelpers"; 197import { CompilerDriver } from "./compilerDriver"; 198import { getLiteralKey } from "./base/util"; 199import { AsyncGeneratorState } from "./function/asyncGeneratorFunctionBuilder"; 200 201export enum FunctionKind { 202 NONE = 0, // represent method for now 203 FUNCTION = 1, 204 NC_FUNCTION = 2, 205 GENERATOR_FUNCTION = 3, 206 ASYNC_FUNCTION = 4, 207 ASYNC_GENERATOR_FUNCTION = 5, 208 ASYNC_NCFUNCTION = 6 209} 210export class PandaGen { 211 // @ts-ignore 212 private debugTag: string = "PandaGen"; 213 readonly internalName: string; 214 private node: ts.SourceFile | ts.FunctionLikeDeclaration; 215 private parametersCount: number; 216 private locals: VReg[] = []; 217 private temps: VReg[] = []; 218 private insns: IRNode[] = []; 219 private instTypeMap: Map<IRNode, number> = new Map<IRNode, number>(); 220 private scope: Scope | undefined; 221 private vregisterCache: VregisterCache; 222 private catchMap: Map<Label, CatchTable> = new Map<Label, CatchTable>(); 223 private totalRegsNum = 0; 224 // for debug info 225 private variableDebugInfoArray: VariableDebugInfo[] = []; 226 private firstStmt: ts.Statement | undefined; 227 private sourceFile: string = ""; 228 private sourceCode: string | undefined = undefined; 229 private callType: number = 0; 230 private funcKind: FunctionKind = FunctionKind.NONE; 231 private icSize: number = 0; 232 233 private static literalArrayBuffer: Array<LiteralBuffer> = new Array<LiteralBuffer>(); 234 235 constructor(internalName: string, node: ts.SourceFile | ts.FunctionLikeDeclaration, 236 parametersCount: number, scope: Scope | undefined = undefined) { 237 this.internalName = internalName; 238 this.node = node; 239 this.parametersCount = parametersCount; 240 this.scope = scope; 241 this.vregisterCache = new VregisterCache(); 242 this.setFunctionKind(node); 243 } 244 245 public appendScopeInfo(lexVarInfo: Map<string, number>): string | undefined { 246 if (lexVarInfo.size === 0) { 247 return undefined; 248 } 249 250 let scopeInfoId: string | undefined = undefined; 251 let scopeInfo = new LiteralBuffer(); 252 let scopeInfoLiterals = new Array<Literal>(); 253 scopeInfoLiterals.push(new Literal(LiteralTag.INTEGER, lexVarInfo.size)); 254 lexVarInfo.forEach((slot: number, name: string) => { 255 scopeInfoLiterals.push(new Literal(LiteralTag.STRING, name)); 256 scopeInfoLiterals.push(new Literal(LiteralTag.INTEGER, slot)); 257 }); 258 scopeInfo.addLiterals(...scopeInfoLiterals); 259 scopeInfoId = PandaGen.appendLiteralArrayBuffer(scopeInfo); 260 return scopeInfoId; 261 } 262 263 public setFunctionKind(node: ts.SourceFile | ts.FunctionLikeDeclaration) { 264 if (ts.isSourceFile(node)) { 265 this.funcKind = FunctionKind.FUNCTION; 266 return; 267 } 268 269 if (ts.isMethodDeclaration(node)) { 270 return; 271 } 272 273 if (node.modifiers) { 274 for (let i = 0; i < node.modifiers.length; i++) { 275 if (node.modifiers[i].kind === ts.SyntaxKind.AsyncKeyword) { 276 if (node.asteriskToken) { 277 this.funcKind = FunctionKind.ASYNC_GENERATOR_FUNCTION; 278 return; 279 } 280 281 if (ts.isArrowFunction(node)) { 282 this.funcKind = FunctionKind.ASYNC_NCFUNCTION; 283 return; 284 } 285 286 this.funcKind = FunctionKind.ASYNC_FUNCTION; 287 return; 288 } 289 } 290 } 291 292 if (node.asteriskToken) { 293 this.funcKind = FunctionKind.GENERATOR_FUNCTION; 294 return; 295 } 296 297 if (ts.isArrowFunction(node)) { 298 this.funcKind = FunctionKind.NC_FUNCTION; 299 return; 300 } 301 302 this.funcKind = FunctionKind.FUNCTION; 303 } 304 305 public getFunctionKind() { 306 return this.funcKind; 307 } 308 309 public setCallType(callType: number) { 310 this.callType = callType; 311 } 312 313 public getCallType(): number { 314 return this.callType; 315 } 316 317 public updateIcSize(icSlot: number) { 318 this.icSize += icSlot; 319 } 320 321 public getIcSize() { 322 return this.icSize; 323 } 324 325 static getExportedTypes() { 326 if (TypeRecorder.getInstance()) { 327 return TypeRecorder.getInstance().getExportedType(); 328 } else { 329 return new Map<string, number>(); 330 } 331 } 332 333 static getDeclaredTypes() { 334 if (TypeRecorder.getInstance()) { 335 return TypeRecorder.getInstance().getDeclaredType(); 336 } else { 337 return new Map<string, number>(); 338 } 339 } 340 341 public getSourceCode(): string | undefined { 342 return this.sourceCode; 343 } 344 345 public setSourceCode(code: string) { 346 this.sourceCode = code; 347 } 348 349 public getSourceFileDebugInfo() { 350 return this.sourceFile; 351 } 352 353 public setSourceFileDebugInfo(sourceFile: string) { 354 this.sourceFile = sourceFile; 355 } 356 357 static getLiteralArrayBuffer() { 358 return PandaGen.literalArrayBuffer; 359 } 360 361 static clearLiteralArrayBuffer() { 362 PandaGen.literalArrayBuffer = []; 363 } 364 365 getParameterLength() { 366 if (this.scope instanceof FunctionScope) { 367 return this.scope.getParameterLength(); 368 } 369 } 370 371 getFuncName() { 372 if (this.scope instanceof FunctionScope) { 373 return this.scope.getFuncName(); 374 } else { 375 return "main"; 376 } 377 } 378 379 static appendLiteralArrayBuffer(litBuf: LiteralBuffer): string { 380 let litId = getLiteralKey(CompilerDriver.srcNode, PandaGen.literalArrayBuffer.length); 381 litBuf.setKey(litId); 382 PandaGen.literalArrayBuffer.push(litBuf); 383 return litId; 384 } 385 386 static appendTypeArrayBuffer(type: BaseType): number { 387 let index = PandaGen.literalArrayBuffer.length; 388 let typeBuf = type.transfer2LiteralBuffer(); 389 typeBuf.setKey(getLiteralKey(CompilerDriver.srcNode, index)); 390 PandaGen.literalArrayBuffer.push(typeBuf); 391 return index; 392 } 393 394 static setTypeArrayBuffer(type: BaseType, index: number) { 395 let typeBuf = type.transfer2LiteralBuffer(); 396 typeBuf.setKey(getLiteralKey(CompilerDriver.srcNode, index)); 397 PandaGen.literalArrayBuffer[index] = typeBuf; 398 } 399 400 getFirstStmt(): ts.Statement { 401 return this.firstStmt; 402 } 403 404 setFirstStmt(firstStmt: ts.Statement): void { 405 if (this.firstStmt) { 406 return; 407 } 408 this.firstStmt = firstStmt; 409 } 410 411 getVregisterCache(): VregisterCache { 412 return this.vregisterCache; 413 } 414 415 getCatchMap(): Map<Label, CatchTable> { 416 return this.catchMap; 417 } 418 419 getScope(): Scope | undefined { 420 return this.scope; 421 } 422 423 getVariableDebugInfoArray(): VariableDebugInfo[] { 424 return this.variableDebugInfoArray; 425 } 426 427 addDebugVariableInfo(variable: VariableDebugInfo): void { 428 this.variableDebugInfoArray.push(variable); 429 } 430 431 allocLocalVreg(): VReg { 432 let vreg = new VReg(); 433 this.locals.push(vreg); 434 return vreg; 435 } 436 437 getVregForVariable(v: Variable): VReg { 438 if (v.hasAlreadyBinded()) { 439 return v.getVreg(); 440 } 441 let vreg = this.allocLocalVreg(); 442 v.bindVreg(vreg); 443 return vreg; 444 } 445 446 getTemp(): VReg { 447 let retval: VReg; 448 if (this.temps.length > 0) { 449 retval = this.temps.shift()!; 450 } else { 451 retval = new VReg(); 452 } 453 454 return retval; 455 } 456 457 freeTemps(...temps: VReg[]): void { 458 this.temps.unshift(...temps); 459 } 460 461 getInsns(): IRNode[] { 462 return this.insns; 463 } 464 465 setInsns(insns: IRNode[]): void { 466 this.insns = insns; 467 } 468 469 printInsns(): void { 470 LOGE("function " + this.internalName + "() {"); 471 this.getInsns().forEach(ins => { 472 LOGE(ins.toString()); 473 }) 474 LOGE("}"); 475 } 476 477 setTotalRegsNum(num: number): void { 478 this.totalRegsNum = num; 479 } 480 481 getTotalRegsNum(): number { 482 return this.totalRegsNum; 483 } 484 485 setParametersCount(count: number): void { 486 this.parametersCount = count; 487 } 488 489 getParametersCount(): number { 490 return this.parametersCount; 491 } 492 493 setLocals(locals: VReg[]): void { 494 this.locals = locals; 495 } 496 497 getLocals(): VReg[] { 498 return this.locals; 499 } 500 501 getTemps(): VReg[] { 502 return this.temps; 503 } 504 505 getInstTypeMap(): Map<IRNode, number> { 506 return this.instTypeMap; 507 } 508 509 getNode(): ts.SourceFile | ts.FunctionLikeDeclaration { 510 return this.node; 511 } 512 513 storeAccumulator(node: ts.Node | NodeKind, vreg: VReg): void { 514 this.add(node, storeAccumulator(vreg)); 515 } 516 517 generatorYield(node: ts.Node, genObj: VReg): void { 518 this.add( 519 node, 520 loadAccumulator(genObj), 521 new Setgeneratorstate(new Imm(AsyncGeneratorState.SUSPENDYIELD)) 522 ) 523 } 524 525 generatorComplete(node: ts.Node | NodeKind, genObj: VReg): void { 526 this.add( 527 node, 528 loadAccumulator(genObj), 529 new Setgeneratorstate(new Imm(AsyncGeneratorState.COMPLETED)) 530 ) 531 } 532 533 loadAccFromArgs(node: ts.Node): void { 534 if ((<VariableScope>this.scope).getUseArgs()) { 535 let v = this.scope!.findLocal(MandatoryArguments); 536 if (this.scope instanceof FunctionScope) { 537 this.scope.setArgumentsOrRestargs(); 538 } 539 if (v) { 540 let paramVreg = this.getVregForVariable(v); 541 this.getUnmappedArgs(node); 542 this.add(node, storeAccumulator(paramVreg)); 543 } else { 544 throw new Error("fail to get arguments"); 545 } 546 } 547 } 548 549 deleteObjProperty(node: ts.Node, obj: VReg): void { 550 this.add(node, deleteObjProperty(obj)); 551 } 552 553 loadAccumulator(node: ts.Node | NodeKind, vreg: VReg): void { 554 this.add(node, loadAccumulator(vreg)); 555 } 556 557 createLexEnv(node: ts.Node, scope: VariableScope | LoopScope): void { 558 let numVars = scope.getNumLexEnv(); 559 let scopeInfoId: string | undefined = undefined; 560 let lexVarInfo = scope.getLexVarInfo(); 561 if (CmdOptions.isDebugMode()) { 562 scopeInfoId = this.appendScopeInfo(lexVarInfo); 563 } 564 565 this.add( 566 node, 567 newLexicalEnv(numVars, scopeInfoId), 568 ) 569 } 570 571 newLexicalEnv(node, numVars: number): void { 572 this.add( 573 node, 574 newLexicalEnv(numVars, undefined), 575 ) 576 } 577 578 popLexicalEnv(node: ts.Node): void { 579 this.add( 580 node, 581 popLexicalEnv() 582 ) 583 } 584 585 loadAccFromLexEnv(node: ts.Node, scope: Scope, level: number, v: Variable): void { 586 let expander = new VariableAccessLoad(scope, level, v); 587 let insns = expander.expand(this); 588 this.add( 589 node, 590 ...insns 591 ); 592 } 593 594 storeAccToLexEnv(node: ts.Node | NodeKind, scope: Scope, level: number, v: Variable, isDeclaration: boolean): void { 595 let expander = new VariableAcessStore(scope, level, v, isDeclaration, node); 596 let insns = expander.expand(this); 597 this.add( 598 node, 599 ...insns 600 ) 601 } 602 603 loadObjProperty(node: ts.Node, obj: VReg, prop: VReg | string | number): void { 604 switch (typeof (prop)) { 605 case "number": { 606 if (isInteger(prop)) { 607 this.loadObjByIndex(node, obj, prop); 608 } else { 609 let propReg = this.getTemp(); 610 this.add( 611 node, 612 loadAccumulatorFloat(prop), 613 storeAccumulator(propReg), 614 ); 615 this.loadObjByValue(node, obj, propReg); 616 this.freeTemps(propReg); 617 } 618 break; 619 } 620 case "string": 621 this.loadObjByName(node, obj, prop); 622 break; 623 default: 624 this.loadObjByValue(node, obj, prop); 625 } 626 } 627 628 storeObjProperty(node: ts.Node | NodeKind, obj: VReg, prop: VReg | string | number): void { 629 switch (typeof (prop)) { 630 case "number": 631 if (isInteger(prop)) { 632 this.storeObjByIndex(node, obj, prop); 633 } else { 634 let valueReg = this.getTemp(); 635 let propReg = this.getTemp(); 636 this.storeAccumulator(node, valueReg); 637 this.add( 638 node, 639 loadAccumulatorFloat(prop), 640 storeAccumulator(propReg), 641 loadAccumulator(valueReg) 642 ); 643 this.storeObjByValue(node, obj, propReg); 644 this.freeTemps(valueReg, propReg); 645 } 646 break; 647 case "string": 648 this.storeObjByName(node, obj, prop); 649 break; 650 default: 651 this.storeObjByValue(node, obj, prop); 652 } 653 } 654 655 storeOwnProperty(node: ts.Node | NodeKind, obj: VReg, prop: VReg | string | number, nameSetting: boolean = false): void { 656 switch (typeof prop) { 657 case "number": { 658 if (isInteger(prop)) { 659 this.stOwnByIndex(node, obj, prop); 660 } else { 661 let valueReg = this.getTemp(); 662 let propReg = this.getTemp(); 663 this.storeAccumulator(node, valueReg); 664 this.add( 665 node, 666 loadAccumulatorFloat(prop), 667 storeAccumulator(propReg), 668 loadAccumulator(valueReg) 669 ); 670 this.stOwnByValue(node, obj, propReg, nameSetting); 671 this.freeTemps(valueReg, propReg); 672 } 673 break; 674 } 675 case "string": 676 this.stOwnByName(node, obj, prop, nameSetting); 677 break; 678 default: 679 this.stOwnByValue(node, obj, prop, nameSetting); 680 } 681 } 682 683 private loadObjByName(node: ts.Node, obj: VReg, string_id: string): void { 684 this.add( 685 node, 686 loadAccumulator(obj), 687 loadObjByName(string_id) 688 ); 689 } 690 691 private storeObjByName(node: ts.Node | NodeKind, obj: VReg, string_id: string): void { 692 this.add( 693 node, 694 storeObjByName(obj, string_id) 695 ); 696 } 697 698 private loadObjByIndex(node: ts.Node, obj: VReg, index: number): void { 699 this.add( 700 node, 701 loadAccumulator(obj), 702 loadObjByIndex(index) 703 ) 704 } 705 706 private storeObjByIndex(node: ts.Node | NodeKind, obj: VReg, index: number): void { 707 this.add( 708 node, 709 storeObjByIndex(obj, index) 710 ) 711 } 712 713 714 private loadObjByValue(node: ts.Node, obj: VReg, value: VReg): void { 715 this.add( 716 node, 717 loadAccumulator(value), 718 loadObjByValue(obj) 719 ) 720 } 721 722 private storeObjByValue(node: ts.Node | NodeKind, obj: VReg, prop: VReg): void { 723 this.add( 724 node, 725 storeObjByValue(obj, prop) 726 ) 727 } 728 729 private stOwnByName(node: ts.Node | NodeKind, obj: VReg, string_id: string, nameSetting: boolean): void { 730 this.add(node, storeOwnByName(obj, string_id, nameSetting)); 731 } 732 733 private stOwnByIndex(node: ts.Node | NodeKind, obj: VReg, index: number): void { 734 this.add(node, storeOwnByIndex(obj, index)); 735 } 736 737 private stOwnByValue(node: ts.Node | NodeKind, obj: VReg, value: VReg, nameSetting: boolean): void { 738 this.add(node, storeOwnByValue(obj, value, nameSetting)); 739 } 740 741 loadByNameViaDebugger(node: ts.Node, string_id: string, boolVal: CacheList): void { 742 this.loadObjProperty(node, getVregisterCache(this, CacheList.GLOBAL), "debuggerGetValue"); 743 let getValueReg = this.getTemp(); 744 this.storeAccumulator(node, getValueReg); 745 let variableReg = this.getTemp(); 746 this.loadAccumulatorString(node, string_id); 747 this.storeAccumulator(node, variableReg); 748 let trueValueReg = this.getTemp(); 749 this.moveVreg(node, trueValueReg, getVregisterCache(this, boolVal)); 750 this.call(node, [getValueReg, variableReg, trueValueReg], false); 751 this.freeTemps(getValueReg, variableReg, trueValueReg); 752 } 753 754 // eg. print 755 tryLoadGlobalByName(node: ts.Node, string_id: string): void { 756 CmdOptions.isWatchEvaluateExpressionMode() ? this.loadByNameViaDebugger(node, string_id, CacheList.TRUE) : 757 this.add(node, tryLoadGlobalByName(string_id)); 758 } 759 760 storeByNameViaDebugger(node: ts.Node, string_id: string): void { 761 let valueReg = this.getTemp(); 762 this.storeAccumulator(node, valueReg); 763 this.loadObjProperty(node, getVregisterCache(this, CacheList.GLOBAL), "debuggerSetValue"); 764 let setValueReg = this.getTemp(); 765 this.storeAccumulator(node, setValueReg); 766 let variableReg = this.getTemp(); 767 this.loadAccumulatorString(node, string_id); 768 this.storeAccumulator(node, variableReg); 769 this.call(node, [setValueReg, variableReg, valueReg], false); 770 this.freeTemps(valueReg, setValueReg, variableReg); 771 } 772 773 // eg. a = 1 774 tryStoreGlobalByName(node: ts.Node, string_id: string): void { 775 CmdOptions.isWatchEvaluateExpressionMode() ? this.storeByNameViaDebugger(node, string_id) : 776 this.add(node, tryStoreGlobalByName(string_id)); 777 } 778 779 // eg. var n; n; 780 loadGlobalVar(node: ts.Node, string_id: string): void { 781 this.add( 782 node, 783 loadGlobalVar(string_id)); 784 } 785 786 // var n = 1; 787 storeGlobalVar(node: ts.Node | NodeKind, string_id: string): void { 788 this.add( 789 node, 790 storeGlobalVar(string_id)); 791 } 792 793 loadAccumulatorString(node: ts.Node | NodeKind, str: string): void { 794 this.add(node, loadAccumulatorString(str)); 795 } 796 797 loadAccumulatorFloat(node: ts.Node, num: number): void { 798 this.add(node, loadAccumulatorFloat(num)); 799 } 800 801 loadAccumulatorInt(node: ts.Node, num: number): void { 802 this.add(node, loadAccumulatorInt(num)); 803 } 804 805 moveVreg(node: ts.Node | NodeKind, vd: VReg, vs: VReg): void { 806 this.add(node, moveVreg(vd, vs)); 807 } 808 809 // @ts-ignore 810 label(node: ts.Node, label: Label): void { 811 this.add(NodeKind.INVALID, label); 812 } 813 814 branch(node: ts.Node | NodeKind, target: Label): void { 815 this.add(node, jumpTarget(target)); 816 } 817 818 branchIfNotUndefined(node: ts.Node, target: Label): void { 819 // the compared value is in acc 820 this.condition(node, ts.SyntaxKind.EqualsEqualsToken, getVregisterCache(this, CacheList.UNDEFINED), target); 821 } 822 823 branchIfUndefined(node: ts.Node, target: Label): void { 824 // the compared value is in acc 825 this.condition(node, ts.SyntaxKind.ExclamationEqualsToken, getVregisterCache(this, CacheList.UNDEFINED), target) 826 } 827 828 isTrue(node: ts.Node): void { 829 this.add( 830 node, 831 isTrue() 832 ) 833 } 834 835 jumpIfTrue(node: ts.Node, target: Label): void { 836 this.isFalse(node); 837 this.add( 838 node, 839 new Jeqz(target) 840 ) 841 } 842 843 isFalse(node: ts.Node): void { 844 this.add( 845 node, 846 isFalse() 847 ) 848 } 849 850 jumpIfFalse(node: ts.Node, target: Label): void { 851 this.isTrue(node); 852 this.add( 853 node, 854 new Jeqz(target) 855 ) 856 } 857 858 debugger(node: ts.Node): void { 859 this.add(node, creatDebugger()); 860 } 861 862 throwUndefinedIfHole(node: ts.Node, name: string): void { 863 this.add( 864 node, 865 throwUndefinedIfHole(name) 866 ) 867 } 868 869 less(node: ts.Node, lhs: VReg): void { 870 this.add(node, new Less(new Imm(0), lhs)); 871 } 872 873 greater(node: ts.Node, lhs: VReg): void { 874 this.add(node, new Greater(new Imm(0), lhs)); 875 } 876 877 greaterEq(node: ts.Node, lhs: VReg): void { 878 this.add(node, new Greatereq(new Imm(0), lhs)); 879 } 880 881 lessEq(node: ts.Node, lhs: VReg): void { 882 this.add(node, new Lesseq(new Imm(0), lhs)); 883 } 884 885 equal(node: ts.Node, lhs: VReg): void { 886 this.add(node, new Eq(new Imm(0), lhs)); 887 } 888 889 notEqual(node: ts.Node, lhs: VReg): void { 890 this.add(node, new Noteq(new Imm(0), lhs)); 891 } 892 893 strictEqual(node: ts.Node, lhs: VReg): void { 894 this.add(node, new Stricteq(new Imm(0), lhs)); 895 } 896 897 strictNotEqual(node: ts.Node, lhs: VReg): void { 898 this.add(node, new Strictnoteq(new Imm(0), lhs)); 899 } 900 901 /** 902 * The method generates code for ther following cases 903 * if (lhs OP acc) {...} 904 * ifFalse: ... 905 */ 906 condition(node: ts.Node, op: SyntaxKind, lhs: VReg, ifFalse: Label): void { 907 // Please keep order of cases the same as in types.ts 908 switch (op) { 909 case SyntaxKind.LessThanToken: // line 57 910 this.less(node, lhs); 911 this.add(node, new Jeqz(ifFalse)); 912 break; 913 case SyntaxKind.GreaterThanToken: // line 59 914 this.greater(node, lhs); 915 this.add(node, new Jeqz(ifFalse)); 916 break; 917 case SyntaxKind.LessThanEqualsToken: // line 60 918 this.lessEq(node, lhs); 919 this.add(node, new Jeqz(ifFalse)); 920 break; 921 case SyntaxKind.GreaterThanEqualsToken: // line 61 922 this.greaterEq(node, lhs); 923 this.add(node, new Jeqz(ifFalse)); 924 break; 925 case SyntaxKind.EqualsEqualsToken: // line 62 926 this.equal(node, lhs); 927 this.add(node, new Jeqz(ifFalse)); 928 break; 929 case SyntaxKind.ExclamationEqualsToken: // line 63 930 this.notEqual(node, lhs); 931 this.add(node, new Jeqz(ifFalse)); 932 break; 933 case SyntaxKind.EqualsEqualsEqualsToken: // line 64 934 this.strictEqual(node, lhs); 935 this.add(node, new Jeqz(ifFalse)); 936 break; 937 case SyntaxKind.ExclamationEqualsEqualsToken: // line 65 938 this.strictNotEqual(node, lhs); 939 this.add(node, new Jeqz(ifFalse)); 940 break; 941 default: 942 break; 943 } 944 } 945 946 unary(node: ts.Node, op: PrefixUnaryOperator, operand: VReg): void { 947 switch (op) { 948 case SyntaxKind.PlusToken: 949 this.toNumber(node, operand); 950 break; 951 case SyntaxKind.MinusToken: 952 this.add( 953 node, 954 loadAccumulator(operand), 955 new Neg(new Imm(0))); 956 break; 957 case SyntaxKind.PlusPlusToken: 958 this.add( 959 node, 960 loadAccumulator(operand), 961 new Inc(new Imm(0))); 962 break; 963 case SyntaxKind.MinusMinusToken: 964 this.add( 965 node, 966 loadAccumulator(operand), 967 new Dec(new Imm(0))); 968 break; 969 case SyntaxKind.ExclamationToken: 970 let falseLabel = new Label(); 971 let endLabel = new Label(); 972 this.jumpIfFalse(node, falseLabel); 973 // operand is true 974 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.FALSE))); 975 this.branch(node, endLabel); 976 // operand is false 977 this.label(node, falseLabel); 978 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.TRUE))); 979 this.label(node, endLabel); 980 break; 981 case SyntaxKind.TildeToken: 982 this.add( 983 node, 984 loadAccumulator(operand), 985 new Not(new Imm(0))); 986 break; 987 default: 988 throw new Error("Unimplemented"); 989 } 990 } 991 992 binary(node: ts.Node, op: BinaryOperator, lhs: VReg): void { 993 switch (op) { 994 case SyntaxKind.LessThanToken: // line 57 995 case SyntaxKind.GreaterThanToken: // line 59 996 case SyntaxKind.LessThanEqualsToken: // line 60 997 case SyntaxKind.GreaterThanEqualsToken: // line 61 998 case SyntaxKind.EqualsEqualsToken: // line 62 999 case SyntaxKind.ExclamationEqualsToken: // line 63 1000 case SyntaxKind.EqualsEqualsEqualsToken: // line 64 1001 case SyntaxKind.ExclamationEqualsEqualsToken: // line 65 1002 this.binaryRelation(node, op, lhs); 1003 break; 1004 case SyntaxKind.PlusToken: // line 67 1005 case SyntaxKind.PlusEqualsToken: // line 91 1006 this.add(node, new Add2(new Imm(0), lhs)); 1007 break; 1008 case SyntaxKind.MinusToken: // line 68 1009 case SyntaxKind.MinusEqualsToken: // line 92 1010 this.add(node, new Sub2(new Imm(0), lhs)); 1011 break; 1012 case SyntaxKind.AsteriskToken: // line 69 1013 case SyntaxKind.AsteriskEqualsToken: // line 93 1014 this.add(node, new Mul2(new Imm(0), lhs)); 1015 break; 1016 case SyntaxKind.AsteriskAsteriskToken: // line 70 1017 case SyntaxKind.AsteriskAsteriskEqualsToken: // line 94 1018 this.add(node, new Exp(new Imm(0), lhs)); 1019 break; 1020 case SyntaxKind.SlashToken: // line 71 1021 case SyntaxKind.SlashEqualsToken: // line 95 1022 this.add(node, new Div2(new Imm(0), lhs)); 1023 break; 1024 case SyntaxKind.PercentToken: // line 72 1025 case SyntaxKind.PercentEqualsToken: // line 96 1026 this.add(node, new Mod2(new Imm(0), lhs)); 1027 break; 1028 case SyntaxKind.LessThanLessThanToken: // line 75 1029 case SyntaxKind.LessThanLessThanEqualsToken: // line 97 1030 this.add(node, new Shl2(new Imm(0), lhs)); 1031 break; 1032 case SyntaxKind.GreaterThanGreaterThanToken: // line 76 1033 case SyntaxKind.GreaterThanGreaterThanEqualsToken: // line 98 1034 this.add(node, new Ashr2(new Imm(0), lhs)); 1035 break; 1036 case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: // line 77 1037 case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: // line 99 1038 this.add(node, new Shr2(new Imm(0), lhs)); 1039 break; 1040 case SyntaxKind.AmpersandToken: // line 78 1041 case SyntaxKind.AmpersandEqualsToken: // line 100 1042 this.add(node, new And2(new Imm(0), lhs)); 1043 break; 1044 case SyntaxKind.BarToken: // line 79 1045 case SyntaxKind.BarEqualsToken: // line 101 1046 this.add(node, new Or2(new Imm(0), lhs)); 1047 break; 1048 case SyntaxKind.CaretToken: // line 80 1049 case SyntaxKind.CaretEqualsToken: // line 102 1050 this.add(node, new Xor2(new Imm(0), lhs)); 1051 break; 1052 case SyntaxKind.InKeyword: //line 125 1053 // The in operator returns true if the specified property is in the specified object or its prototype chain 1054 this.add(node, new Isin(new Imm(0), lhs)); 1055 break; 1056 case SyntaxKind.InstanceOfKeyword: //line 126 1057 // The instanceof operator tests to see if the prototype property of 1058 // a constructor appears anywhere in the prototype chain of an object. 1059 // The return value is a boolean value. 1060 this.add(node, new Instanceof(new Imm(0), lhs)); 1061 break; 1062 default: 1063 throw new Error("Unimplemented"); 1064 } 1065 } 1066 1067 // throw needs argument of exceptionVreg 1068 // to ensure rethrow the exception after finally 1069 throw(node: ts.Node): void { 1070 this.add( 1071 node, 1072 throwException() 1073 ); 1074 } 1075 1076 throwThrowNotExist(node: ts.Node): void { 1077 this.add(node, throwThrowNotExists()); 1078 } 1079 1080 throwDeleteSuperProperty(node: ts.Node): void { 1081 this.add(node, throwDeleteSuperProperty()); 1082 } 1083 1084 throwConstAssignment(node: ts.Node, nameReg: VReg): void { 1085 this.add(node, throwConstAssignment(nameReg)); 1086 } 1087 1088 return(node: ts.Node | NodeKind): void { 1089 this.add(node, new Return()); 1090 } 1091 1092 call(node: ts.Node, args: VReg[], passThis: boolean): void { 1093 this.add( 1094 node, 1095 loadAccumulator(args[0]), // callee is stored in acc 1096 call(args.slice(1), passThis) 1097 ) 1098 } 1099 1100 returnUndefined(node: ts.Node | NodeKind): void { 1101 this.add( 1102 node, 1103 returnUndefined() 1104 ) 1105 } 1106 1107 newObject(node: ts.Node, args: VReg[]): void { 1108 this.add( 1109 node, 1110 newObject(args) 1111 ); 1112 } 1113 1114 defineMethod(node: ts.FunctionLikeDeclaration, name: string, objReg: VReg): void { 1115 let paramLength = getParamLengthOfFunc(node); 1116 this.add( 1117 node, 1118 loadAccumulator(objReg), 1119 defineMethod(name, paramLength) 1120 ); 1121 } 1122 1123 defineFunction(node: ts.FunctionLikeDeclaration | NodeKind, realNode: ts.FunctionLikeDeclaration, name: string): void { 1124 let paramLength = getParamLengthOfFunc(realNode); 1125 this.add( 1126 node, 1127 defineFunc(name, paramLength) 1128 ); 1129 } 1130 1131 typeOf(node: ts.Node): void { 1132 this.add(node, new Typeof(new Imm(0))); 1133 } 1134 1135 callSpread(node: ts.Node, func: VReg, thisReg: VReg, args: VReg): void { 1136 this.loadAccumulator(node, func); 1137 this.add(node, new Apply(new Imm(0), thisReg, args)); 1138 } 1139 1140 newObjSpread(node: ts.Node, obj: VReg): void { 1141 this.add(node, new Newobjapply(new Imm(0), obj)); 1142 } 1143 1144 getUnmappedArgs(node: ts.Node): void { 1145 this.add(node, new Getunmappedargs()); 1146 } 1147 1148 toNumber(node: ts.Node, arg: VReg): void { 1149 this.loadAccumulator(node, arg); 1150 this.add(node, new Tonumber(new Imm(0))); 1151 } 1152 1153 toNumeric(node: ts.Node, arg: VReg): void { 1154 this.loadAccumulator(node, arg); 1155 this.add(node, new Tonumeric(new Imm(0))); 1156 } 1157 1158 createGeneratorObj(node: ts.Node, funcObj: VReg): void { 1159 this.add(node, new Creategeneratorobj(funcObj)); 1160 } 1161 1162 createAsyncGeneratorObj(node: ts.Node, funcObj: VReg): void { 1163 this.add(node, new Createasyncgeneratorobj(funcObj)); 1164 } 1165 1166 Createiterresultobj(node: ts.Node, value: VReg, done: VReg): void { 1167 this.add(node, new Createiterresultobj(value, done)); 1168 } 1169 1170 asyncgeneratorresolve(node: ts.Node | NodeKind, genObj: VReg, value: VReg, done: VReg): void { 1171 this.add(node, new Asyncgeneratorresolve(genObj, value, done)); 1172 } 1173 1174 asyncgeneratorreject(node: ts.Node, genObj: VReg): void { 1175 this.add(node, new Asyncgeneratorreject(genObj)); 1176 } 1177 1178 suspendGenerator(node: ts.Node | NodeKind, genObj: VReg): void { 1179 this.add(node, new Suspendgenerator(genObj)); // promise obj is in acc 1180 } 1181 1182 resumeGenerator(node: ts.Node | NodeKind, genObj: VReg): void { 1183 this.add( 1184 node, 1185 loadAccumulator(genObj), 1186 new Resumegenerator()); 1187 } 1188 1189 getResumeMode(node: ts.Node | NodeKind, genObj: VReg): void { 1190 this.add( 1191 node, 1192 loadAccumulator(genObj), 1193 new Getresumemode()); 1194 } 1195 1196 asyncFunctionEnter(node: ts.Node | NodeKind): void { 1197 this.add(node, new Asyncfunctionenter()); 1198 } 1199 1200 asyncFunctionAwaitUncaught(node: ts.Node | NodeKind, asynFuncObj: VReg): void { 1201 this.add(node, new Asyncfunctionawaituncaught(asynFuncObj)); // received value is in acc 1202 } 1203 1204 asyncFunctionResolve(node: ts.Node | NodeKind, asyncObj: VReg): void { 1205 this.add(node, new Asyncfunctionresolve(asyncObj)); // use retVal in acc 1206 } 1207 1208 asyncFunctionReject(node: ts.Node | NodeKind, asyncObj: VReg): void { 1209 this.add(node, new Asyncfunctionreject(asyncObj)); // exception is in acc 1210 } 1211 1212 getTemplateObject(node: ts.Node | NodeKind, value: VReg): void { 1213 this.loadAccumulator(node, value); 1214 this.add(node, new Gettemplateobject(new Imm(0))); 1215 } 1216 1217 copyRestArgs(node: ts.Node, index: number): void { 1218 this.add(node, 1219 index <= MAX_INT8 ? new Copyrestargs(new Imm(index)) : new WideCopyrestargs(new Imm(index))); 1220 } 1221 1222 getPropIterator(node: ts.Node): void { 1223 this.add(node, getPropIterator()); 1224 } 1225 1226 getNextPropName(node: ts.Node, iter: VReg): void { 1227 this.add(node, getNextPropName(iter)); 1228 } 1229 1230 createEmptyObject(node: ts.Node): void { 1231 this.add(node, createEmptyObject()); 1232 } 1233 1234 createObjectWithBuffer(node: ts.Node, bufferId: string): void { 1235 this.add(node, createObjectWithBuffer(bufferId)); 1236 } 1237 1238 setObjectWithProto(node: ts.Node, proto: VReg, object: VReg): void { 1239 this.add( 1240 node, 1241 loadAccumulator(object), 1242 setObjectWithProto(proto)); 1243 } 1244 1245 copyDataProperties(node: ts.Node, dstObj: VReg): void { 1246 this.add(node, copyDataProperties(dstObj)); 1247 } 1248 1249 defineGetterSetterByValue(node: ts.Node, obj: VReg, name: VReg, getter: VReg, setter: VReg, isComputedPropertyName: boolean): void { 1250 if (isComputedPropertyName) { 1251 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.TRUE))); 1252 } else { 1253 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.FALSE))); 1254 } 1255 this.add(node, defineGetterSetterByValue(obj, name, getter, setter)); 1256 } 1257 1258 createEmptyArray(node: ts.Node): void { 1259 this.add(node, createEmptyArray()); 1260 } 1261 1262 createArrayWithBuffer(node: ts.Node, bufferId: string): void { 1263 this.add(node, createArrayWithBuffer(bufferId)); 1264 } 1265 1266 storeArraySpreadElement(node: ts.Node, array: VReg, index: VReg): void { 1267 this.add(node, storeArraySpread(array, index)); 1268 } 1269 1270 storeLexicalVar(node: ts.Node, level: number, slot: number, value: VReg): void { 1271 this.loadAccumulator(node, value); // value is load to acc 1272 this.add( 1273 node, 1274 storeLexicalVar(level, slot) 1275 ); 1276 } 1277 1278 loadLexicalVar(node: ts.Node, level: number, slot: number): void { 1279 this.add( 1280 node, 1281 loadLexicalVar(level, slot) 1282 ) 1283 } 1284 1285 loadModuleVariable(node: ts.Node, v: ModuleVariable, isLocal: boolean): void { 1286 let index: number = v.getIndex(); 1287 let typeIndex: number = v.getTypeIndex(); 1288 // For local module variable, we bind type with storeModuleVariable instruction 1289 // instead of loadLocalModuleVariable instruction to avoid duplicate recording when load multi times. 1290 // For external module variable, we can only bind type with loadExternalModuleVariable instruction 1291 // because there is no storeModuleVariable instruction of the corrsponding variable in the same file. 1292 if (isLocal) { 1293 this.add(node, loadLocalModuleVariable(index)); 1294 } else { 1295 let ldModuleVarInst: IRNode = loadExternalModuleVariable(index); 1296 this.setInstType(ldModuleVarInst, typeIndex); 1297 this.add(node, ldModuleVarInst); 1298 } 1299 } 1300 1301 storeModuleVariable(node: ts.Node | NodeKind, v: ModuleVariable): void { 1302 let index: number = v.getIndex(); 1303 let typeIndex: number = v.getTypeIndex(); 1304 let stModuleVarInst: IRNode = storeModuleVariable(index); 1305 this.setInstType(stModuleVarInst, typeIndex); 1306 this.add(node, stModuleVarInst); 1307 } 1308 1309 getModuleNamespace(node: ts.Node, moduleRequestIdx: number): void { 1310 this.add(node, getModuleNamespace(moduleRequestIdx)); 1311 } 1312 1313 dynamicImportCall(node: ts.Node): void { 1314 this.add(node, dynamicImport()); 1315 } 1316 1317 defineClassWithBuffer(node: ts.Node, name: string, litId: string, parameterLength: number, base: VReg): void { 1318 this.add( 1319 node, 1320 defineClassWithBuffer(name, litId, parameterLength, base) 1321 ) 1322 } 1323 1324 createObjectWithExcludedKeys(node: ts.Node, obj: VReg, args: VReg[]): void { 1325 this.add( 1326 node, 1327 createObjectWithExcludedKeys(obj, args) 1328 ); 1329 } 1330 1331 throwObjectNonCoercible(node: ts.Node): void { 1332 this.add( 1333 node, 1334 throwObjectNonCoercible() 1335 ); 1336 } 1337 1338 getIterator(node: ts.Node): void { 1339 this.add( 1340 node, 1341 getIterator() 1342 ); 1343 } 1344 1345 getAsyncIterator(node: ts.Node): void { 1346 this.add( 1347 node, 1348 new Getasynciterator(new Imm(0)) 1349 ) 1350 } 1351 1352 closeIterator(node: ts.Node, iter: VReg): void { 1353 this.add( 1354 node, 1355 closeIterator(iter) 1356 ) 1357 } 1358 1359 throwIfNotObject(node: ts.Node, obj: VReg): void { 1360 this.add( 1361 node, 1362 throwIfNotObject(obj) 1363 ); 1364 } 1365 1366 superCall(node: ts.Node, num: number, args: Array<VReg>): void { 1367 if (ts.isArrowFunction(jshelpers.getContainingFunction(node))) { 1368 this.add( 1369 node, 1370 superCallInArrow(num, args) 1371 ) 1372 return; 1373 } 1374 1375 this.add( 1376 node, 1377 superCall(num, args) 1378 ) 1379 } 1380 1381 superCallSpread(node: ts.Node, vs: VReg): void { 1382 this.add(node, superCallSpread(vs)); 1383 } 1384 1385 ldSuperByName(node: ts.Node, obj: VReg, key: string): void { 1386 this.add( 1387 node, 1388 loadAccumulator(obj), 1389 ldSuperByName(key) 1390 ) 1391 } 1392 1393 stSuperByName(node: ts.Node, obj: VReg, key: string): void { 1394 this.add( 1395 node, 1396 stSuperByName(obj, key) 1397 ) 1398 } 1399 1400 ldSuperByValue(node: ts.Node, obj: VReg): void { 1401 this.add( 1402 node, 1403 ldSuperByValue(obj) 1404 ) 1405 } 1406 1407 stSuperByValue(node: ts.Node, obj: VReg, prop: VReg): void { 1408 this.add( 1409 node, 1410 stSuperByValue(obj, prop) 1411 ) 1412 } 1413 1414 loadSuperProperty(node: ts.Node, obj: VReg, prop: VReg | string | number): void { 1415 switch (typeof (prop)) { 1416 case "string": 1417 this.ldSuperByName(node, obj, prop); 1418 break; 1419 case "number": 1420 this.loadAccumulatorInt(node, prop); 1421 this.ldSuperByValue(node, obj); 1422 break; 1423 default: 1424 this.loadAccumulator(node, prop); 1425 this.ldSuperByValue(node, obj); 1426 } 1427 } 1428 1429 throwIfSuperNotCorrectCall(node: ts.Node, num: number): void { 1430 this.add(node, throwIfSuperNotCorrectCall(num)); 1431 } 1432 1433 storeSuperProperty(node: ts.Node, obj: VReg, prop: VReg | string | number): void { 1434 switch (typeof (prop)) { 1435 case "string": 1436 this.stSuperByName(node, obj, prop); 1437 break; 1438 case "number": 1439 let propReg = this.getTemp(); 1440 this.loadAccumulatorInt(node, prop); 1441 this.storeAccumulator(node, propReg); 1442 this.stSuperByValue(node, obj, propReg); 1443 this.freeTemps(propReg); 1444 break; 1445 default: 1446 this.stSuperByValue(node, obj, prop); 1447 } 1448 } 1449 1450 createRegExpWithLiteral(node: ts.Node, pattern: string, flags: number): void { 1451 this.add( 1452 node, 1453 createRegExpWithLiteral(pattern, flags) 1454 ) 1455 } 1456 1457 stLetOrClassToGlobalRecord(node: ts.Node, string_id: string): void { 1458 this.add( 1459 node, 1460 stLetOrClassToGlobalRecord(string_id)); 1461 } 1462 1463 stConstToGlobalRecord(node: ts.Node, string_id: string): void { 1464 this.add( 1465 node, 1466 stConstToGlobalRecord(string_id)); 1467 } 1468 1469 loadAccumulatorBigInt(node: ts.Node | NodeKind, str: string): void { 1470 this.add( 1471 node, 1472 loadAccumulatorBigInt(str)); 1473 } 1474 1475 storeConst(node: ts.Node | NodeKind, dst: VReg, value: CacheList): void { 1476 this.loadAccumulator(node, getVregisterCache(this, value)); 1477 this.storeAccumulator(node, dst); 1478 } 1479 1480 private binaryRelation(node: ts.Node, op: BinaryOperator, lhs: VReg): void { 1481 let falseLabel = new Label(); 1482 let endLabel = new Label(); 1483 switch (op) { 1484 case SyntaxKind.LessThanToken: 1485 this.less(node, lhs); 1486 break; 1487 case SyntaxKind.GreaterThanToken: 1488 this.greater(node, lhs); 1489 break; 1490 case SyntaxKind.LessThanEqualsToken: 1491 this.lessEq(node, lhs); 1492 break; 1493 case SyntaxKind.GreaterThanEqualsToken: 1494 this.greaterEq(node, lhs); 1495 break; 1496 case SyntaxKind.EqualsEqualsToken: 1497 this.equal(node, lhs); 1498 break; 1499 case SyntaxKind.ExclamationEqualsToken: 1500 this.notEqual(node, lhs); 1501 break; 1502 case SyntaxKind.EqualsEqualsEqualsToken: 1503 this.strictEqual(node, lhs); 1504 break; 1505 case SyntaxKind.ExclamationEqualsEqualsToken: 1506 this.strictNotEqual(node, lhs); 1507 break; 1508 default: 1509 break; 1510 } 1511 this.add(node, new Jeqz(falseLabel)); 1512 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.TRUE))); 1513 this.branch(node, endLabel); 1514 this.label(node, falseLabel); 1515 this.add(node, loadAccumulator(getVregisterCache(this, CacheList.FALSE))); 1516 this.label(node, endLabel); 1517 } 1518 1519 private add(node: ts.Node | NodeKind, ...insns: IRNode[]): void { 1520 // set pos debug info if debug mode 1521 DebugInfo.setDebuginfoForIns(node, ...insns); 1522 1523 this.insns.push(...insns); 1524 } 1525 1526 public setInstType(inst: IRNode, typeId: number | undefined): void { 1527 if (typeId != undefined && TypeRecorder.getInstance() != undefined) { 1528 this.instTypeMap.set(inst, typeId); 1529 } 1530 } 1531} 1532