• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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