Class NpcRolloutDifferTest
java.lang.Object
scripting.NpcRolloutDifferTest
Track B(Nashorn → GraalJS)— C5 rollout③:npc 類別黃金參考 differ。
對應計畫 C5 的出口條件「Tier2+Tier3 differ 過關」。npc 是逐類別 rollout 第三棒
(portal=C3、reactor=C4),也是語料量最大的一類(924 個 scripts/npc/*.js)。本檔與
reactor/portal differ 同骨架,差異在進入點與並發模型:
- 進入點:npc 線上以
engine.put("cm", ..)+invokeFunction("start")(或回退action((byte)1,(byte)0,0))驅動,玩家點選後再invokeFunction("action", mode, type, selection)(見NPCScriptManager.start(MapleClient, int)/NPCScriptManager.action(MapleClient, byte, byte, int))。故 Tier2 轉錄走start/action,Tier3 綁定 parity 以「typeof start與typeof action逐檔跨引擎一致」驗證(線上實際呼叫路徑)。 - 快取/執行緒模型(關鍵,異於 C3/C4):npc 引擎為 per-client 快取
(
AbstractScriptManager→MapleClient.getScriptEngine(String)),且NPCScriptManager的全部六個進入點(start/action/startQuest/endQuest/onUserEnter/ onFirstUserEnter)皆先取c.getNPCLock()(per-clientnpc_mutex)、並橫跨getInvocable(含 compile+eval) +invokeFunction全程持鎖。npc 引擎確實會被 off-Netty 執行緒進入(GMCommandCrucialTime走 EventTimer;MapScriptMethods/MapleMap的 EtcTimer/EventTimer →onUserEnter/onFirstUserEnter),但每條路徑 都先取同一把 per-clientnpc_mutex→ 不可能兩執行緒同時進同一 client 的 Context。 這正是 reactor(C4)缺、而 npc 天生具備的保護:reactor 的act()曾被 MapTimer 無鎖 進入 Context 才需補 per-(client,rid) 鎖;npc 無對應的無鎖進入,故 不需新增任何鎖。 本檔下半的並發回歸組在引擎層證明「per-clientReentrantLock(即npc_mutex)序列化即足」, 並文件化該鎖對 GraalJS 已成 load-bearing(防未來重構誤拔)。
同一 JVM 並存 nashorn-core(黃金參考)與 GraalJS(候選),由
ScriptEngines.fresh(ScriptEngines.Backend) 建立。不需 DB / wz / 網路 / Timer。
(語料偵察 + 對抗審查由 workflow 完成:全 924 檔零 E4X/Java.type/importClass/
JavaAdapter;唯一 interop 為 load('nashorn:mozilla_compat.js')(11 檔)+
importPackage(13 檔),兩引擎在 js.nashorn-compat=true 下走相同路徑、parity。
並發審查 3 lens × refute-by-default 皆未能反駁「npc 不需新鎖」。)
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classstatic final class受信任第一方腳本以HostAccess.ALL直呼本物件的 public 方法 —— 與線上cm(NPCConversationManager)同樣的 host-interop 路徑。 -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoid全scripts/npc/*.js在 nashorn-core 與 GraalJS 必須等價(非「全部成功」): 解析分歧(XOR)= 零:不得有任何腳本「一引擎解析成功、另一引擎失敗」。void合成微 fixture 補語料缺口:全 npc 語料中 無「未鏈接cm.getMeso()的 flatcm.gainMeso(整數字面)」(每個 gainMeso 都閘在 getPlayer().getMeso() 之後),故以一行腳本 直驗gainMeso(int)的數值強制 parity(避免 Tier2 該維度空白)。voidvoid重現通用危害:單一共用 GraalJS Context 被兩執行緒同時invokeFunction("start")→ 拋多執行緒例外(或一度重疊)。void
-
Constructor Details
-
NpcRolloutDifferTest
public NpcRolloutDifferTest()
-
-
Method Details
-
corpusParseAndStartActionBindingAreEngineEquivalent
全scripts/npc/*.js在 nashorn-core 與 GraalJS 必須等價(非「全部成功」):- 解析分歧(XOR)= 零:不得有任何腳本「一引擎解析成功、另一引擎失敗」。E4X/Nashorn-only 語法殘留會在此現形 —— rollout 硬門檻。(workflow 已掃全 924 檔:零真 E4X。)
- start/action 綁定逐檔等價:eval(容忍頂層丟)後
typeof start與typeof action兩引擎須各自一致 —— 驗NPCScriptManager線上實際走的invokeFunction("start"|"action")路徑。
「兩引擎皆解析失敗」≠ 分歧(記錄到
build/npc-parse-broken-both.txt,不擋 rollout)。 註:小寫importpackage(...)打錯的兩檔(9270035.js/9900007.js)語法合法 → compile 成功,僅 eval 時兩引擎皆拋ReferenceError(函式宣告已 hoist,故typeof start仍一致)→ 落在 parity 內、非 broken-both。- Throws:
Exception
-
tier2TranscriptsMatchAcrossEngines
-
gainMesoIntCoercionMatchesAcrossEngines
-
perClientNpcMutexSerializesConcurrentEntry
佐證:套上 per-clientReentrantLock(即線上npc_mutex對所有進入點的作法)→ 無例外、maxInFlight<=1。此即「npc 不需新增鎖」的根據:既有 npc_mutex 已序列化 Context 進入。 亦文件化:該鎖對 GraalJS 已 load-bearing,未來重構不可拔。- Throws:
Exception
-