← All issues

[JSC] Move RegExp.prototype[Symbol.match] to C++

e922a2c

JSTests/stress/regexp-prototype-symbol-match-watchpoint-invalidation.js

+function match(re, str) { return re[Symbol.match](str); }
+...
+(function() {
+ // specialization 이후 exec를 override
+ custom.exec = function(...) { ... };
+ shouldThrow(() => match(re, "hello"), ...);
+})();
+...
+(function() {
+ // RegExp.prototype.exec를 전역으로 override
+ RegExp.prototype.exec = function() { throw new Error("custom exec"); };
+ shouldThrow(() => match(re, "hello"), ...);
+})();

RegExp.prototype[Symbol.match]String.prototype.match와 직접적인 re[Symbol.match](str) 호출 모두의 진입점입니다. 사양이 요구하는 알고리즘은 겉보기보다 복잡한데, global 또는 sticky regexp에서는 RegExpExec를 반복 호출하면서 ToLengthlastIndex를 coerce해야 합니다. 빈 match는 AdvanceStringIndex를 통해 건너뛰어야 하며, 이 함수는 Unicode를 인식하고 surrogate pair를 올바르게 처리하도록 되어 있습니다. 또한 exec, flags, lastIndex accessor가 override된 경우의 observable side effect도 빠짐없이 준수해야 합니다. JSC는 이전까지 이 기능을 JS builtin으로 구현해왔으나, 이번 commit에서 native C++로 이식하였습니다.

이번 패치에서는 hasObservableSideEffectsForRegExpMatchmatchSlow JS helper가 제거되었습니다. 대신 DFG에는 새로운 addRegExpMatchPrimordialChecks 함수가 도입되었으며, C++ 구현에도 전용 advanceStringIndex helper와 regExpMatchSlow fallback 경로가 추가되었습니다. DFG compiler의 새로운 primordial-check 시스템이 fast C++ 경로를 제어합니다. 관련 built-in이 모두 수정되지 않은 상태라면 fast C++ exec loop로 진입하고, 하나라도 수정되어 있으면 regExpMatchSlow로 fallback됩니다.

Before:                              After:
  str.match(re)                        str.match(re)
    └─► String.prototype.match (C++)     └─► String.prototype.match (C++)
          └─► RegExp.prototype                 └─► RegExp.prototype
              [Symbol.match]  ← JS builtin         [Symbol.match]  ← C++ host
                ├─ hasObservableSideEffects        ├─ addRegExpMatchPrimordialChecks
                ├─ matchSlow()                     │     ├─ intact → fast C++ exec loop
                └─ exec() loop                     │     └─ modified → regExpMatchSlow()
                                                   └─ advanceStringIndex() ← new C++

5~25%의 성능 향상 외에도, 이번 변경은 spec이 요구하는 복잡한 로직을 interpreter 수준의 JS builtin에서 C++로 이동시킵니다. 여기에는 lastIndex coercion, 빈 match 진행, Unicode surrogate 처리, observable side effect 감지가 포함됩니다. C++ 구현에서는 spec과의 구현 차이를 발견하기가 더 어렵고, 역사적으로 이런 차이가 exploit 가능한 버그로 이어진 사례가 있습니다. 새로운 primordial check의 정확성이 spec이 요구하는 observable side effect가 실제로 관찰되는지를 결정하게 됩니다.

🔒

The new primordial-check gate and Unicode advancement path each have edge cases worth security investigation.

더 확인하려면 구독해 주세요