稍微在吉里吉里2.28的源代码里找了下TJS2 VM的执行机制,主要着眼于dispatch loop的实现,并且找到了下面的代码:

kirikiri2\src\core\tjs2\tjsInterCodeExec.cpp/972:

tjs_int tTJSInterCodeContext::ExecuteCode(tTJSVariant *ra_org, tjs_int startip,    tTJSVariant **args, tjs_int numargs, tTJSVariant *result){    // execute VM codes    tjs_int32 *codesave;    try    {        tjs_int32 *code = codesave = CodeArea + startip;

        if(TJSStackTracerEnabled()) TJSStackTracerSetCodePointer(CodeArea, &codesave);

        tTJSVariant *ra = ra_org;        tTJSVariant *da = DataArea;

        bool flag = false;

        while(true)        {            codesave = code;            switch(*code)            {            case VM_NOP:                code ++;                break;

            case VM_CONST:                TJS_GET_VM_REG(ra, code[1]).CopyRef(TJS_GET_VM_REG(da, code[2]));                code += 3;                break;

            case VM_CP:                TJS_GET_VM_REG(ra, code[1]).CopyRef(TJS_GET_VM_REG(ra, code[2]));                code += 3;                break;

            case VM_CL:                TJS_GET_VM_REG(ra, code[1]).Clear();                code += 2;                break;

            case VM_CCL:                ContinuousClear(ra, code);                code += 3;                break;

            case VM_TT:                flag = TJS_GET_VM_REG(ra, code[1]).operator bool();                code += 2;                break;

            case VM_TF:                flag = !(TJS_GET_VM_REG(ra, code[1]).operator bool());                code += 2;                break;

            case VM_CEQ:                flag = TJS_GET_VM_REG(ra, code[1]).NormalCompare(                    TJS_GET_VM_REG(ra, code[2]));                code += 3;                break;

            case VM_CDEQ:                flag = TJS_GET_VM_REG(ra, code[1]).DiscernCompare(                    TJS_GET_VM_REG(ra, code[2]));                code += 3;                break;

            case VM_CLT:                flag = TJS_GET_VM_REG(ra, code[1]).GreaterThan(                    TJS_GET_VM_REG(ra, code[2]));                code += 3;                break;

            case VM_CGT:                flag = TJS_GET_VM_REG(ra, code[1]).LittlerThan(                    TJS_GET_VM_REG(ra, code[2]));                code += 3;                break;

            case VM_SETF:                TJS_GET_VM_REG(ra, code[1]) = flag;                code += 2;                break;

            case VM_SETNF:                TJS_GET_VM_REG(ra, code[1]) = !flag;                code += 2;                break;

            case VM_LNOT:                TJS_GET_VM_REG(ra, code[1]).logicalnot();                code += 2;                break;

            case VM_NF:                flag = !flag;                code ++;                break;

            case VM_JF:                if(flag)                    TJS_ADD_VM_CODE_ADDR(code, code[1]);                else                    code += 2;                break;

            case VM_JNF:                if(!flag)                    TJS_ADD_VM_CODE_ADDR(code, code[1]);                else                    code += 2;                break;

            case VM_JMP:                TJS_ADD_VM_CODE_ADDR(code, code[1]);                break;

            case VM_INC:                TJS_GET_VM_REG(ra, code[1]).increment();                code += 2;                break;

            case VM_INCPD:                OperatePropertyDirect0(ra, code, TJS_OP_INC);                code += 4;                break;

            case VM_INCPI:                OperatePropertyIndirect0(ra, code, TJS_OP_INC);                code += 4;                break;

            case VM_INCP:                OperateProperty0(ra, code, TJS_OP_INC);                code += 3;                break;

            case VM_DEC:                TJS_GET_VM_REG(ra, code[1]).decrement();                code += 2;                break;

            case VM_DECPD:                OperatePropertyDirect0(ra, code, TJS_OP_DEC);                code += 4;                break;

            case VM_DECPI:                OperatePropertyIndirect0(ra, code, TJS_OP_DEC);                code += 4;                break;

            case VM_DECP:                OperateProperty0(ra, code, TJS_OP_DEC);                code += 3;                break;

#define TJS_DEF_VM_P(vmcode, rope) \            case VM_##vmcode: \                TJS_GET_VM_REG(ra, code[1]).rope(TJS_GET_VM_REG(ra, code[2])); \                code += 3; \                break; \            case VM_##vmcode##PD: \                OperatePropertyDirect(ra, code, TJS_OP_##vmcode); \                code += 5; \                break; \            case VM_##vmcode##PI: \                OperatePropertyIndirect(ra, code, TJS_OP_##vmcode); \                code += 5; \                break; \            case VM_##vmcode##P: \                OperateProperty(ra, code, TJS_OP_##vmcode); \                code += 4; \                break

                TJS_DEF_VM_P(LOR, logicalorequal);                TJS_DEF_VM_P(LAND, logicalandequal);                TJS_DEF_VM_P(BOR, operator |=);                TJS_DEF_VM_P(BXOR, operator ^=);                TJS_DEF_VM_P(BAND, operator &=);                TJS_DEF_VM_P(SAR, operator >>=);                TJS_DEF_VM_P(SAL, operator <<=);                TJS_DEF_VM_P(SR, rbitshiftequal);                TJS_DEF_VM_P(ADD, operator +=);                TJS_DEF_VM_P(SUB, operator -=);                TJS_DEF_VM_P(MOD, operator %=);                TJS_DEF_VM_P(DIV, operator /=);                TJS_DEF_VM_P(IDIV, idivequal);                TJS_DEF_VM_P(MUL, operator *=);

#undef TJS_DEF_VM_P

            case VM_BNOT:                TJS_GET_VM_REG(ra, code[1]).bitnot();                code += 2;                break;

            case VM_ASC:                CharacterCodeOf(TJS_GET_VM_REG(ra, code[1]));                code += 2;                break;

            case VM_CHR:                CharacterCodeFrom(TJS_GET_VM_REG(ra, code[1]));                code += 2;                break;

            case VM_NUM:                TJS_GET_VM_REG(ra, code[1]).tonumber();                code += 2;                break;

            case VM_CHS:                TJS_GET_VM_REG(ra, code[1]).changesign();                code += 2;                break;

            case VM_INV:                TJS_GET_VM_REG(ra, code[1]) =                    (TJS_GET_VM_REG(ra,                    code[1]).AsObjectClosureNoAddRef().Invalidate(0,                    NULL, NULL, ra[-1].AsObjectNoAddRef()) == TJS_S_TRUE);                code += 2;                break;

            case VM_CHKINV:                TJS_GET_VM_REG(ra, code[1]) =                    TJSIsObjectValid(TJS_GET_VM_REG(ra,                    code[1]).AsObjectClosureNoAddRef().IsValid(0,                    NULL, NULL, ra[-1].AsObjectNoAddRef()));                code += 2;                break;

            case VM_INT:                TJS_GET_VM_REG(ra, code[1]).ToInteger();                code += 2;                break;

            case VM_REAL:                TJS_GET_VM_REG(ra, code[1]).ToReal();                code += 2;                break;

            case VM_STR:                TJS_GET_VM_REG(ra, code[1]).ToString();                code += 2;                break;

            case VM_OCTET:                TJS_GET_VM_REG(ra, code[1]).ToOctet();                code += 2;                break;

            case VM_TYPEOF:                TypeOf(TJS_GET_VM_REG(ra, code[1]));                code += 2;                break;

            case VM_TYPEOFD:                TypeOfMemberDirect(ra, code, TJS_MEMBERMUSTEXIST);                code += 4;                break;

            case VM_TYPEOFI:                TypeOfMemberIndirect(ra, code, TJS_MEMBERMUSTEXIST);                code += 4;                break;

            case VM_EVAL:                Eval(TJS_GET_VM_REG(ra, code[1]),                    TJSEvalOperatorIsOnGlobal ? NULL : ra[-1].AsObjectNoAddRef(),                    true);                code += 2;                break;

            case VM_EEXP:                Eval(TJS_GET_VM_REG(ra, code[1]),                    TJSEvalOperatorIsOnGlobal ? NULL : ra[-1].AsObjectNoAddRef(),                    false);                code += 2;                break;

            case VM_CHKINS:                InstanceOf(TJS_GET_VM_REG(ra, code[2]),                    TJS_GET_VM_REG(ra, code[1]));                code += 3;                break;

            case VM_CALL:            case VM_NEW:                code += CallFunction(ra, code, args, numargs);                break;

            case VM_CALLD:                code += CallFunctionDirect(ra, code, args, numargs);                break;

            case VM_CALLI:                code += CallFunctionIndirect(ra, code, args, numargs);                break;

            case VM_GPD:                GetPropertyDirect(ra, code, 0);                code += 4;                break;

            case VM_GPDS:                GetPropertyDirect(ra, code, TJS_IGNOREPROP);                code += 4;                break;

            case VM_SPD:                SetPropertyDirect(ra, code, 0);                code += 4;                break;

            case VM_SPDE:                SetPropertyDirect(ra, code, TJS_MEMBERENSURE);                code += 4;                break;

            case VM_SPDEH:                SetPropertyDirect(ra, code, TJS_MEMBERENSURE|TJS_HIDDENMEMBER);                code += 4;                break;

            case VM_SPDS:                SetPropertyDirect(ra, code, TJS_MEMBERENSURE|TJS_IGNOREPROP);                code += 4;                break;

            case VM_GPI:                GetPropertyIndirect(ra, code, 0);                code += 4;                break;

            case VM_GPIS:                GetPropertyIndirect(ra, code, TJS_IGNOREPROP);                code += 4;                break;

            case VM_SPI:                SetPropertyIndirect(ra, code, 0);                code += 4;                break;

            case VM_SPIE:                SetPropertyIndirect(ra, code, TJS_MEMBERENSURE);                code += 4;                break;

            case VM_SPIS:                SetPropertyIndirect(ra, code, TJS_MEMBERENSURE|TJS_IGNOREPROP);                code += 4;                break;

            case VM_GETP:                GetProperty(ra, code);                code += 3;                break;

            case VM_SETP:                SetProperty(ra, code);                code += 3;                break;

            case VM_DELD:                DeleteMemberDirect(ra, code);                code += 4;                break;

            case VM_DELI:                DeleteMemberIndirect(ra, code);                code += 4;                break;

            case VM_SRV:                if(result) result->CopyRef(TJS_GET_VM_REG(ra, code[1]));                code += 2;                break;

            case VM_RET:                return code+1-CodeArea;

            case VM_ENTRY:                code = CodeArea + ExecuteCodeInTryBlock(ra, code-CodeArea + 3, args,                    numargs, result, TJS_FROM_VM_CODE_ADDR(code[1])+code-CodeArea,                    TJS_FROM_VM_REG_ADDR(code[2]));                break;

            case VM_EXTRY:                return code+1-CodeArea;  // same as ret

            case VM_THROW:                ThrowScriptException(TJS_GET_VM_REG(ra, code[1]),                    Block, CodePosToSrcPos(code-CodeArea));                code += 2; // actually here not proceed...                break;

            case VM_CHGTHIS:                TJS_GET_VM_REG(ra, code[1]).ChangeClosureObjThis(                    TJS_GET_VM_REG(ra, code[2]).AsObjectNoAddRef());                code += 3;                break;

            case VM_GLOBAL:                TJS_GET_VM_REG(ra, code[1]) = Block->GetTJS()->GetGlobalNoAddRef();                code += 2;                break;

            case VM_ADDCI:                AddClassInstanceInfo(ra, code);                code+=3;                break;

            case VM_REGMEMBER:                RegisterObjectMember(ra[-1].AsObjectNoAddRef());                code ++;                break;

            case VM_DEBUGGER:                TJSNativeDebuggerBreak();                code ++;                break;

            default:                ThrowInvalidVMCode();            }        }    }    catch(eTJSSilent &e)    {        throw e;    }    catch(eTJSScriptException &e)    {        e.AddTrace(this, codesave-CodeArea);        throw e;    }    catch(eTJSScriptError &e)    {        e.AddTrace(this, codesave-CodeArea);        throw e;    }    catch(eTJS &e)    {        DisplayExceptionGeneratedCode(codesave - CodeArea, ra_org);        TJS_eTJSScriptError(e.GetMessage(), this, codesave-CodeArea);    }    catch(exception &e)    {        DisplayExceptionGeneratedCode(codesave - CodeArea, ra_org);        TJS_eTJSScriptError(e.what(), this, codesave-CodeArea);    }    catch(const wchar_t *text)    {        DisplayExceptionGeneratedCode(codesave - CodeArea, ra_org);        TJS_eTJSScriptError(text, this, codesave-CodeArea);    }    catch(const char *text)    {        DisplayExceptionGeneratedCode(codesave - CodeArea, ra_org);        TJS_eTJSScriptError(text, this, codesave-CodeArea);    }#ifdef TJS_SUPPORT_VCL    catch(const EAccessViolation &e)    {        DisplayExceptionGeneratedCode(codesave - CodeArea, ra_org);        TJS_eTJSScriptError(e.Message.c_str(), this, codesave-CodeArea);    }    catch(const Exception &e)    {        DisplayExceptionGeneratedCode(codesave - CodeArea, ra_org);        TJS_eTJSScriptError(e.Message.c_str(), this, codesave-CodeArea);    }#endif

    return codesave-CodeArea;}

果然还是相当典型且直观的解释器。这种不断读入VM码(在每个case之后决定code的增量),并通过单一的switch语句来完成dispatch的方法,是基本解释器实现里最直观,但通常也是最慢的方式。
对于一个比较小的指令集(例如RISC),threaded code通常是更好的解决方案,因为在每个指令例程的最后添加跳转操作能减少现代CPU的跳转预测失误。其中又有indirected与directed这两大类的threadeding。[url=http://www.complang.tuwien.ac.at/anton/home.html]Anton Ertl[/url]有篇[url=http://www.complang.tuwien.ac.at/forth/threaded-code.html]关于threaded code不错的文章[/url]。在[url=http://www.amazon.com/Virtual-Machines-Versatile-Platforms-Architecture/dp/1558609105]Virtual Machines: Versatile Platforms for Systems and Processes[/url]一书中有更详细的解释。
TJS2 VM现有的实现有不少让人很想吐槽的地方,例如说基于引用计数的GC,还有那难以阅读的代码……那么大量的宏用起来真够难受的。
其实W.Dee氏之所以宁可直接开始实现吉里吉里3的Risse VM而不在现有的吉里吉里2的codebase上修改,恐怕也是因为这codebase太乱了吧。新的Risse VM已经有了不少实质性的改进,例如用Boehm GC来代替原本不太好的引用计数GC;将中间表示(IR)改进为SSA形式,等等。不过就这么那TJS2 VM扔掉也怪可惜的。想慢慢把TJS2 VM中可改进的地方挖出来,看看是否适合给予改进。如果能赶在吉里吉里3的Risse VM完成前对TJS2 VM做些改进,那还算有价值。

不过吉里吉里系列内的VM有个很紧的要求,那就是整个运行时的外表看起来要像一个解释器,即:内部实现是先将文本形式的脚本源代码编译为中间表现,然后再由VM执行(此处的VM又是一个真正的解释器)。这对编译的部分要求比较高,使一些耗时间的优化不太好进行。要是W.Dee氏肯接受真正完整的编译,再交由VM执行,会轻松很多。

(试想一下,写一个程序把Java Compiler与JVM包装起来,像解释脚本一样执行Java源文件。如果你用的是Sun的JDK,恭喜你,编译HelloWorld可能也要半分钟。而且JDK 1.6.0系列还经常诡异的出现NoClassDefFoundError,让我只好对1.6.0系列敬而远之)

附注:吉里吉里2的源代码基于GPL许可证发布

吉里吉里2中TJS2 VM的dispatch loop相关推荐

  1. 吉里吉里1/吉里吉里2中KAG脚本的解释执行(1)

    从我开始关注吉里吉里2这个引擎开始,就一直看到关于"KAG的执行效率比TJS2低很多"的说法.但是到底慢多少呢?没见到过具体测评. 有机会的话我看看设计一个测评方法好了.关键是看看 ...

  2. 吉里吉里2 2.30版正式发布了

    这应该是不到两个小时之前才发生的事吧--嗯应该还算是新闻. 吉里吉里2 2.30下载点:[url]http://kikyou.info/tvp/[/url] 从2.28到2.30版的变更点: [quo ...

  3. 吉里吉里2相关的一些引用资料

    [url=http://www.aiplus.idv.tw/phpBB2/viewtopic.php?f=28&t=5038][後知後覺]吉里吉里與KAG引擎與Fate/StayNight[/ ...

  4. 吉里吉里2 2.28 rev3发布

    2008/01/22 [quote][list][*]レイヤの重ね合わせ方によってはまれに EAccessViolation 例外が発生していたのを修正 [*]きわめてまれなケース(intervalが ...

  5. 在FlashBuilder里的ActionScript工程中使用Flash CS5中的类 fl.controls库

    在FlashBuilder里的ActionScript工程中使用Flash CS5中的类 1.用Flash CS5打开User Interface.fla文件 我的路径:C:\Program File ...

  6. 360 浏览器设置里安全设置里清除上网痕迹中没有“管理保存过的账号和密码”这个选项

    360浏览器设置里安全设置里清除上网痕迹中没有"管理保存过的账号和密码"这个选项 点击360浏览器右上角"管理"->"管理"里的&qu ...

  7. 计算机配置表中的内存是指什么,电脑里的性能选项中,处理器计划和内存使用所写的是什么意思...

    电脑里的性能选项中,处理器计划和内存使用所写的是什么意思以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 电脑里的性能选项 ...

  8. 重电计算机学院李明建,【i小T有话说 | 第8期】风里雨里,我在上电计算机学院等你!...

    原标题:[i小T有话说 | 第8期]风里雨里,我在上电计算机学院等你! 临港的风为炎炎夏日带来凉意 在这舒服的时节 我们上电计算机又迎来了新的一批小可爱 2019年9月1日上午,各位领导.老师和学长学 ...

  9. 两台xenserver 同一个vlan中的vm 不能ping通?

    我遇到一个问题 我有两台Xenserver, 放到一个pool里面, 创建了一个vlan10的网络 同一台xenserver中的vm之间可以ping通,vm都在vlan10里面. 两台xenserve ...

最新文章

  1. pandas read_csv ‘utf-8‘ codec can‘t decode bytes in position 1198-1199: invalid continuation byte解决
  2. 5 Handler与子线程
  3. 蔡崇信将担任阿里巴巴集团第一组董事
  4. 单身狗应该怎么过七夕节?
  5. 微信小游戏flappy bird填坑
  6. 离散数学及其应用 第一章:集合论
  7. 乔布斯简介及其十大经典语录
  8. 23西南大学电子信息907专硕考研经验贴
  9. 计算机大赛横幅标语有趣的,有创意的横幅标语大全
  10. 【Wing Loss】《Wing Loss for Robust Facial Landmark Localisation with Convolutional Neural Networks》
  11. EAX、ECX、EDX、EBX寄存器的作用
  12. opencv实战——图像矫正算法深入探讨
  13. requests.exceptions.ChunkedEncodingError: (‘Connection broken: IncompleteRead(0 bytes read)‘, Incomp
  14. 未被定义的 “智能座舱”,如何将产业化进行到底
  15. 2022-2028年中国植物蛋白饮品行业市场全景调研及战略咨询研究报告
  16. POWER PIVOT的使用介绍1
  17. netty(五) 【 transferTo 零拷贝实例】
  18. 【Vue】vuex-五个核心
  19. 由于找不到服务器或出现DNS错误
  20. 二维码如何区分微信支付还是支付宝

热门文章

  1. Flutter 开发实战资源推荐
  2. Java日期时间调整的几种方式
  3. 用metaRTC搭建支持H264和H265的linux和嵌入式的高清录播直播系统
  4. win10无限重启_Win 10出现错误代码:0xc0000001
  5. 程序员该不该去外包公司?
  6. 驱动开发:内核枚举DpcTimer定时器
  7. 一款牛逼的微信机器人,已开源!(附源码)
  8. 四旋翼无人机反步法控制器设计(含simulink仿真)
  9. 「 LaTeX 」写论文,IEEE论文插入作者图片IEEEbiography
  10. STM32F429入门(二十一):SPI协议及SPI读写FLASH