Skip to content

Readme Update #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 63 commits into from
Closed

Readme Update #8

wants to merge 63 commits into from

Conversation

anuragpd4
Copy link

No description provided.

For now have ignored the case of posting a message to main run loop.
So it isn't doing much yet.
Who wants to use fork/exec when we have much nicer native APIs?
We need a MIME signature so the roster can find it.
- Added a message handler to look out for incoming messages to runloop
- Created new aux support so we can attach all handlers to the main apps looper
- Added a message stashing feature so it stashes the messages and interprets them when the loop is ready to run
- used maps to store loopers and BApplications to forward message to appropriate loopers
- Created a message from ui process to network process that notifies the pid of webprocess
- Added NetworkSession so it doesnt crash
- Some fixes for ANGLE but keep it disabled (we don't need it)
- Fix various minor things in Haiku specific files
- A bit more cleanup of include files and forwarding headers management
1)This makes few important changes in adding the view
2)Partial mouse events which is kept aside now as main focus is put on webpage rendering
1) Few callbacks for finished loading and forward and backward stop etc is now fully functional
2) status text is partially done
3)shared memory done with mapping part pending(i need to understand a little bit more)
Fix various include path, do not include ANGLE headers when not needed.
Some headers are added to the forwarding headers that probably shouldn't
need to be there (date time chooser stuff, and not sure about image and
image buffer). But it gets things working at least and it's more clean
than what we had before.
1) removed unwanted comments
2) removed unwanted methods
1) Loading, changing title and adding redirected url are added to minibrowser
2) Get data and run on main thread - fixes network process run on main thread problem
1) Put widgets in window thread
2) webkit events on main thread
2) Shareable Bitmap to get data and initialize a bitmap
3) Added few drawing mechanisms to webview
4) Backing store update

Coordinated graphics was briefly enabled here, but it is not needed and
it breaks WebKitLegacy, so for now we keep it off.
1) Loading, changing title and adding redirected url are added to minibrowser
2) Get data and run on main thread - fixes network process run on main thread problem
pulkomandy and others added 21 commits December 10, 2021 21:47
It breaks the build.
…iku [WIP]

Do we need this or can we use the standard one?
Do we still need this? Or can we make this work normally
Still fails to link because somehow WTF is not added to the command
line.
Not sure why the cross platform way to do it isn't working for us...
Not sure if useful or not. But it doesn't seem to break the build.
Make it more similar to other platforms.
-Replaced GCC8 with GCC11
-Added note for disabling ASLR if system runs out of memory
@anuragpd4 anuragpd4 closed this Feb 24, 2022
@anuragpd4 anuragpd4 deleted the readmeupdate branch February 24, 2022 13:57
pulkomandy pushed a commit that referenced this pull request Jul 8, 2022
https://bugs.webkit.org/show_bug.cgi?id=241905

Reviewed by Yusuke Suzuki.

offlineasm used to emit this LLInt code:
    ".loc 1 996\n"        "ldr x19, [x0] \n"                   // LowLevelInterpreter.asm:996
    ".loc 1 997\n"        "ldr x20, [x0, #8] \n"               // LowLevelInterpreter.asm:997
    ".loc 1 998\n"        "ldr x21, [x0, #16] \n"              // LowLevelInterpreter.asm:998
    ".loc 1 999\n"        "ldr x22, [x0, #24] \n"              // LowLevelInterpreter.asm:999
    ...
    ".loc 1 1006\n"       "ldr d8, [x0, WebKit#80] \n"               // LowLevelInterpreter.asm:1006
    ".loc 1 1007\n"       "ldr d9, [x0, WebKit#88] \n"               // LowLevelInterpreter.asm:1007
    ".loc 1 1008\n"       "ldr d10, [x0, WebKit#96] \n"              // LowLevelInterpreter.asm:1008
    ".loc 1 1009\n"       "ldr d11, [x0, WebKit#104] \n"             // LowLevelInterpreter.asm:1009
    ...

Now, it can emit this instead:
    ".loc 1 996\n"        "ldp x19, x20, [x0, #0] \n"          // LowLevelInterpreter.asm:996
    ".loc 1 997\n"        "ldp x21, x22, [x0, #16] \n"         // LowLevelInterpreter.asm:997
    ...
    ".loc 1 1001\n"       "ldp d8, d9, [x0, WebKit#80] \n"           // LowLevelInterpreter.asm:1001
    ".loc 1 1002\n"       "ldp d10, d11, [x0, WebKit#96] \n"         // LowLevelInterpreter.asm:1002
    ...

Also, there was some code that kept recomputing the base address of a sequence of load/store
instructions.  For example,
    ".loc 6 902\n"        "add x13, sp, x10, lsl #3 \n"        // WebAssembly.asm:902
                          "ldr x0, [x13, #48] \n"
                          "add x13, sp, x10, lsl #3 \n"
                          "ldr x1, [x13, #56] \n"
                          "add x13, sp, x10, lsl #3 \n"
                          "ldr x2, [x13, #64] \n"
                          "add x13, sp, x10, lsl #3 \n"
                          "ldr x3, [x13, WebKit#72] \n"
    ...

For such places, we observe that the base address is the same for every load/store instruction
in the sequence, and precompute it in the LLInt asm code to help out the offline asm.  This
allows the offlineasm to now emit this more efficient code instead:
    ".loc 6 896\n"        "add x10, sp, x10, lsl #3 \n"        // WebAssembly.asm:896
    ".loc 6 898\n"        "ldp x0, x1, [x10, #48] \n"          // WebAssembly.asm:898
                          "ldp x2, x3, [x10, #64] \n"
    ...

* Source/JavaScriptCore/llint/LowLevelInterpreter.asm:
* Source/JavaScriptCore/llint/WebAssembly.asm:
* Source/JavaScriptCore/offlineasm/arm64.rb:
* Source/JavaScriptCore/offlineasm/instructions.rb:

Canonical link: https://commits.webkit.org/251799@main
pulkomandy pushed a commit that referenced this pull request Nov 22, 2022
…a rejected promise

https://bugs.webkit.org/show_bug.cgi?id=247785
rdar://102325201

Reviewed by Yusuke Suzuki.

Rest parameter should be caught in async function. So, running this
JavaScript program should print "caught".
```
async function f(...[[]]) { }
f().catch(e => print("caught"));
```

V8 (used console.log)
```
$ node input.js
caught
```

GraalJS
```
$ js input.js
caught
```

https://tc39.es/ecma262/#sec-async-function-definitions
...
AsyncFunctionDeclaration[Yield, Await, Default] :
    async [no LineTerminator here] function BindingIdentifier[?Yield, ?Await] ( FormalParameters[~Yield, +Await] ) { AsyncFunctionBody }
    [+Default] async [no LineTerminator here] function ( FormalParameters[~Yield, +Await] ) { AsyncFunctionBody }

AsyncFunctionExpression :
    async [no LineTerminator here] function BindingIdentifier[~Yield, +Await]opt ( FormalParameters[~Yield, +Await] ) { AsyncFunctionBody }
...

According to the spec, it indicates `FormalParameters` is used for Async
Function, where `FormalParameters` can be converted to `FunctionRestParameter`.

https://tc39.es/ecma262/#sec-parameter-lists
...
FormalParameters[Yield, Await] :
    [empty]
    FunctionRestParameter[?Yield, ?Await]
    FormalParameterList[?Yield, ?Await]
    FormalParameterList[?Yield, ?Await] ,
    FormalParameterList[?Yield, ?Await] , FunctionRestParameter[?Yield, ?Await]
...

And based on RS: EvaluateAsyncFunctionBody, it will invoke the promise.reject
callback function with abrupt value ([[value]] of non-normal completion record).

https://tc39.es/ecma262/#sec-runtime-semantics-evaluateasyncfunctionbody
...
2. Let declResult be Completion(FunctionDeclarationInstantiation(functionObject, argumentsList)).
3. If declResult is an abrupt completion, then
    a. Perform ! Call(promiseCapability.[[Reject]], undefined, « declResult.[[Value]] »).
...

In that case, any non-normal results of evaluating rest parameters should be
caught and passed to the reject callback function.

To resolve this problem, we should allow the emitted RestParameterNode be wrapped
by the catch handler for promise. However, we should remove `m_restParameter` and
emit rest parameter byte code in `initializeDefaultParameterValuesAndSetupFunctionScopeStack`
if we can prove that change has no side effect. In that case, we can only use one
exception handler.

Current fix is to add another exception handler. And move the handler byte codes to
the bottom of code block in order to make other byte codes as much compact as possible.

Input:
```
async function f(arg0, ...[[]]) { }
f();
```

Dumped Byte Codes:
```
...

bb#2
Predecessors: [ #1 ]
[  20] mov                dst:loc9, src:<JSValue()>(const0)
...

bb#3
Predecessors: [ #2 ]
[  29] get_rest_length    dst:loc11, numParametersToSkip:1
...

bb#12
Predecessors: [ #8 #9 #10 ]
[ 138] new_func_exp       dst:loc10, scope:loc4, functionDecl:0
...

bb#13
Predecessors: [ ]
[ 170] catch              exception:loc10, thrownValue:loc8
[ 174] jmp                targetLabel:8(->182)
Successors: [ #15 ]

bb#14
Predecessors: [ #7 #11 ]
[ 176] catch              exception:loc10, thrownValue:loc8
[ 180] jmp                targetLabel:2(->182)
Successors: [ #15 ]

bb#15
Predecessors: [ #13 #14 ]
[ 182] mov                dst:loc12, src:Undefined(const1)
...

Exception Handlers:
	 1: { start: [  20] end: [  29] target: [ 170] } synthesized catch
	 2: { start: [  29] end: [ 138] target: [ 176] } synthesized catch
```

* JSTests/stress/catch-rest-parameter.js: Added.
(throwError):
(shouldThrow):
(async f):
(throwError.async f):
(throwError.async let):
(async let):
(x.async f):
(x):
(async shouldThrow):
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::initializeDefaultParameterValuesAndSetupFunctionScopeStack):
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h:

Canonical link: https://commits.webkit.org/256864@main
pulkomandy pushed a commit that referenced this pull request Mar 5, 2023
https://bugs.webkit.org/show_bug.cgi?id=251063
rdar://104585575

Reviewed by Mark Lam and Justin Michaud.

This patch enhances CallFrame::dump to support wasm frames in btjs stacktrace.
The example is as follows.

    frame #0: 0x00000001035fca78 JavaScriptCore`JSC::functionBreakpoint(globalObject=0x000000012f410068, callFrame=0x000000016fdfa9d0) at JSDollarVM.cpp:2273:9 [opt]
    frame #1: 0x000000010ec44204 0x10eccc5dc
    frame #2: 0x000000010eccc5dc callback#Dwaxn6 [Baseline bc#50](Undefined)
    frame #3: 0x000000010ec4ca84 wasm-stub [WasmToJS](Wasm::Instance: 0x10d29da40)
    frame #4: 0x000000010ed0c060 <?>.wasm-function[1] [OMG](Wasm::Instance: 0x10d29da40)
    frame #5: 0x000000010ed100d0 jsToWasm#CWTx6k [FTL bc#22](Cell[JSModuleEnvironment]: 0x12f524540, Cell[WebAssemblyFunction]: 0x10d06a3a8, 1, 2, 3)
    frame #6: 0x000000010ec881b0 #D5ymZE [Baseline bc#733](Undefined, Cell[Generator]: 0x12f55c180, 1, Cell[Object]: 0x12f69dfc0, 0, Cell[JSLexicalEnvironment]: 0x12f52cee0)
    frame #7: 0x000000010ec3c008 asyncFunctionResume#A4ayYg [LLInt bc#49](Undefined, Cell[Generator]: 0x12f55c180, Cell[Object]: 0x12f69dfc0, 0)
    frame #8: 0x000000010ec3c008 promiseReactionJobWithoutPromise#D0yDF1 [LLInt bc#25](Undefined, Cell[Function]: 0x12f44f3c0, Cell[Object]: 0x12f69dfc0, Cell[Generator]: 0x12f55c180)
    frame #9: 0x000000010ec80ec0 promiseReactionJob#EdShZz [Baseline bc#74](Undefined, Undefined, Cell[Function]: 0x12f44f3c0, Cell[Object]: 0x12f69dfc0, Cell[Generator]: 0x12f55c180)
    frame #10: 0x000000010ec3c728
    frame #11: 0x0000000103137560 JavaScriptCore`JSC::Interpreter::executeCall(JSC::JSGlobalObject*, JSC::JSObject*, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) [inlined] JSC::JITCode::execute(this=<unavailable>, vm=<unavailable>, protoCallFrame=<unavailable>) at JITCodeInlines.h:42:38 [opt]
    frame #12: 0x0000000103137524 JavaScriptCore`JSC::Interpreter::executeCall(this=<unavailable>, lexicalGlobalObject=<unavailable>, function=<unavailable>, callData=<unavailable>, thisValue=<unavailable>, args=<unavailable>) at Interpreter.cpp:1093:27 [opt]
    frame #13: 0x000000010349d6d0 JavaScriptCore`JSC::runJSMicrotask(globalObject=0x000000012f410068, identifier=(m_identifier = 81), job=JSValue @ x22, argument0=JSValue @ x26, argument1=JSValue @ x25, argument2=<unavailable>, argument3=<unavailable>) at JSMicrotask.cpp:98:9 [opt]
    frame #14: 0x00000001039dfc54 JavaScriptCore`JSC::VM::drainMicrotasks() (.cold.1) at VM.cpp:0:9 [opt]
    frame #15: 0x00000001035e58a4 JavaScriptCore`JSC::VM::drainMicrotasks() [inlined] JSC::MicrotaskQueue::dequeue(this=<unavailable>) at VM.cpp:0:9 [opt]
    frame #16: 0x00000001035e5894 JavaScriptCore`JSC::VM::drainMicrotasks(this=0x000000012f000000) at VM.cpp:1255:46 [opt]
    ...

* Source/JavaScriptCore/interpreter/CallFrame.cpp:
(JSC::CallFrame::dump const):

Canonical link: https://commits.webkit.org/259262@main
pulkomandy pushed a commit that referenced this pull request Jan 12, 2025
https://bugs.webkit.org/show_bug.cgi?id=281902
rdar://136486349

Reviewed by Mike Wyrzykowski.

Metal: Ensure potentially infinite loops have defined behavior

The MSL compiler would omit infinite loops and assume number domains
based on the omission logic. This would induce incorrect number domains
in case the infinite loops would be invokable. Infinite loops are
undefined in C++ and thus in MSL. It is the job of the programmer
to ensure undefined behavior cannot happen.

Consider GLSL loop like:
uniform float i;
...
    if (i != 0.5) for(;;) { }
    gl_FragColor = vec4(i);

Historically this would emit MSL loop in spirit of:
    if (i != 0.5) {
      bool c = true;
      while (c) { }
    }
    ANGLE_fragmentOut.gl_FragColor = metal::float4(i, i, i, i);

Since This could cause the MSL compiler to optimize the function to
equivalent of:
    ANGLE_fragmentOut.gl_FragColor = metal::float4(0.5, 0.5, 0.5, 0.5);

Presumably this loop omission would happen at the clang frontend part.

Before, was worked around by emitting asm statements to the MSL:
    bool c = true;
    while (c) {
        __asm__("");
    }

The asm injection would would work for this particular source pattern,
presumably because injecting the asm would avoid the loop omission at
the clang frontend part.

The MSL/C++ code is still UB, though. The asm statement does not cause
anything that C++ would consider as "forward progress" of the loop. The
success was just due to how the backend worked. The bitcode produced
would be similar to:

4:
    tail call void asm sideeffect "", ""() #6, !srcloc !28
    br label %4, !llvm.loop !29

Here, the compiler can be seen to simply fail to detect a loop that
does not make forward progress.

Considering GLSL of form:
uniform int f;
...
    for (;;) { if (f <= 1) break; }

With asm injection to the loop, this would produce:

5:
    tail call void asm sideeffect "", ""() #8, !srcloc !29
    %6 = load i32, i32 addrspace(2)* %4, align 4, !tbaa !30
    %7 = icmp slt i32 %6, 2
    br i1 %7, label %8, label %5
8:

This code is still assumed to make progress. The backend optimizer is
free to assume that the condition holds, since the load to break the
loop is from constant address space. I.e. uniform f does not change its
value during the loop.

Instead of injecting asm, inject a read of unused volatile variable.
The volatile variable access is defined in C++ as forward progress.
This means infinite loop containing such read is considered defined.
To simplify the implementation and to avoid volatile writes, the read
is to a dummy variable instead of the loop condition bool.

The tests here do not pass completely for MSL backend. In case the
compiler would omit the infinite loop (unpatched code), they would fail
with demonstration of how the values behave. After fixing, the loops
cause timeout but Metal backend does not have implementation to report
context loss. Also, the ReadPixels is just for demostration purposes of the
unpatched code.

* Source/ThirdParty/ANGLE/src/compiler/translator/msl/EmitMetal.cpp:
(GenMetalTraverser::GenMetalTraverser):
(GenMetalTraverser::emitLoopBody):
(GenMetalTraverser::emitForwardProgressStore):
(GenMetalTraverser::emitForwardProgressSignal):
(GenMetalTraverser::visitForLoop):
(GenMetalTraverser::visitWhileLoop):
(GenMetalTraverser::visitDoWhileLoop):
* Source/ThirdParty/ANGLE/src/tests/angle_end2end_tests.gni:
* Source/ThirdParty/ANGLE/src/tests/gl_tests/TimeoutDrawTest.cpp: Added.
(angle::TimeoutDrawTest::TimeoutDrawTest):
(angle::TEST_P):

Originally-landed-as: 283286.350@safari-7620-branch (b82d94e). rdar://141318430
Canonical link: https://commits.webkit.org/288020@main
pulkomandy pushed a commit that referenced this pull request Feb 22, 2025
https://bugs.webkit.org/show_bug.cgi?id=288102
rdar://145222010

Reviewed by Yusuke Suzuki.

Added the notion of a string list to a parsed RegExp that is in the form of
  /^(?:break|case|which|do|for)/ with an optional trailing $.
Such a RegExp will not backtrack and therefore we can streamline the code we emit for such a pattern.

This change involves recognizing beginning of string anchored alternations of strings while parsing and
then treating the generation of JIT code differently for these patterns.  This includes changing how
conditional branching works, specifically that instead of the "fall through on match" for each term,
to a "jump on match" for the whole alternation.

The current code generated for the "case" elternative is:
   8:Term PatternCharacter checked-offset:(3) 'c'
               <156> 0x11381430c:    add      w1, w1, #2
               <160> 0x113814310:    cmp      w1, w2
               <164> 0x113814314:    b.hi     0x113814444 -> <468>
  10:Term PatternCharacter checked-offset:(4) 'c'
               <168> 0x113814318:    sub      x17, x0, #4
               <172> 0x11381431c:    ldr      w17, [x17, x1]
               <176> 0x113814320:    movz     w16, #0x6163
               <180> 0x113814324:    movk     w16, #0x6573, lsl #16 -> 0x65736163
               <184> 0x113814328:    cmp      w17, w16
               <188> 0x11381432c:    b.ne     0x113814444 -> <468>
  11:Term PatternCharacter checked-offset:(4) 'a' already handled
  12:Term PatternCharacter checked-offset:(4) 's' already handled
  13:Term PatternCharacter checked-offset:(4) 'e' already handled
  14:NestedAlternativeNext minimum-size:(5),checked-offset:(5)
               <192> 0x113814330:    movz     x16, #0x4444
               <196> 0x113814334:    movk     x16, #0x1381, lsl #16
               <200> 0x113814338:    movk     x16, #0x8001, lsl #32
               <204> 0x11381433c:    movk     x16, #0xc973, lsl #48 -> 0x113814444 JIT PC
               <208> 0x113814340:    stur     x16, [sp, #8]
               <212> 0x113814344:    b        0x113814404 -> <404>
With some additional backtracking code:
   9:NestedAlternativeNext minimum-size:(4),checked-offset:(4)
               <468> 0x113814444:    sub      w1, w1, #2
               <472> 0x113814448:    b        0x113814348 -> <216>

With this change, the processing of "case" becomes:
   9:StringListAlternativeNext minimum-size:(4),checked-offset:(4)
               <132> 0x12a8285c4:    sub      w1, w1, #1
               <136> 0x12a8285c8:    cmp      w1, w2
               <140> 0x12a8285cc:    b.hi     0x12a8285e8 -> <168>
  10:Term PatternCharacter checked-offset:(4) 'c'
               <144> 0x12a8285d0:    sub      x17, x0, #4
               <148> 0x12a8285d4:    ldr      w17, [x17, x1]
               <152> 0x12a8285d8:    movz     w16, #0x6163
               <156> 0x12a8285dc:    movk     w16, #0x6573, lsl #16 -> 0x65736163
               <160> 0x12a8285e0:    cmp      w17, w16
               <164> 0x12a8285e4:    b.eq     0x12a82866c -> <300>
  11:Term PatternCharacter checked-offset:(4) 'a' already handled
  12:Term PatternCharacter checked-offset:(4) 's' already handled
  13:Term PatternCharacter checked-offset:(4) 'e' already handled
  14:StringListAlternativeNext minimum-size:(5),checked-offset:(5)
With no backtracking code.

We are able to eliminate one branch and the saving of the continuation PC for backtracking.
The code size to process these string list RegExp is reduces.  For the example RegExp above,
the prior version created 1940 bytes (485 instructions) of code while the code created with this
1392 bytes (345 instructions) of code, a nearly 30% reduction in code.

This change is a ~18% progression on the new regexp-keyword-parsing microbenchmark:

                                 Baseline               YarrStringList

regexp-keyword-parsing      136.7065+-0.9807     ^    116.0161+-1.1791        ^ definitely 1.1783x faster

<geometric>                 136.7065+-0.9807     ^    116.0161+-1.1791        ^ definitely 1.1783x faster

* JSTests/microbenchmarks/regexp-keyword-parsing.js: Added.
(arrayToString):
(objectToString):
(dumpValue):
(compareArray):
(compareGroups):
(testRegExp):
(testRegExpSyntaxError):
(let.re.break.case.catch.continue.debugger.default.else.finally.if):
(let.re1.break.case.catch.continue.debugger.default.else.finally.if):
* JSTests/stress/regexp-parsing-tokens.js: Added.
(arrayToString):
(objectToString):
(dumpValue):
(compareArray):
(compareGroups):
(testRegExp):
(testRegExpSyntaxError):
* Source/JavaScriptCore/yarr/YarrJIT.cpp:
* Source/JavaScriptCore/yarr/YarrPattern.cpp:
(JSC::Yarr::YarrPatternConstructor::atomParenthesesEnd):
(JSC::Yarr::YarrPatternConstructor::checkForTerminalParentheses):
(JSC::Yarr::PatternAlternative::dump):
(JSC::Yarr::PatternTerm::dump):
* Source/JavaScriptCore/yarr/YarrPattern.h:
(JSC::Yarr::PatternTerm::PatternTerm):
(JSC::Yarr::PatternAlternative::PatternAlternative):

Canonical link: https://commits.webkit.org/290791@main
pulkomandy pushed a commit that referenced this pull request Mar 15, 2025
https://bugs.webkit.org/show_bug.cgi?id=288102
rdar://145222010

Reviewed by Yusuke Suzuki.

Added the notion of a string list to a parsed RegExp that is in the form of
  /^(?:break|case|which|do|for)/ with an optional trailing $.
Such a RegExp will not backtrack and therefore we can streamline the code we emit for such a pattern.

This change involves recognizing beginning of string anchored alternations of strings while parsing and
then treating the generation of JIT code differently for these patterns.  This includes changing how
conditional branching works, specifically that instead of the "fall through on match" for each term,
to a "jump on match" for the whole alternation.

Fixed a bug in the original version where we weren't properly checking the nested alternatives to see
if they only contain fixed single count PatternCharacter terms.

The current code generated for the "case" elternative is:
   8:Term PatternCharacter checked-offset:(3) 'c'
               <156> 0x11381430c:    add      w1, w1, #2
               <160> 0x113814310:    cmp      w1, w2
               <164> 0x113814314:    b.hi     0x113814444 -> <468>
  10:Term PatternCharacter checked-offset:(4) 'c'
               <168> 0x113814318:    sub      x17, x0, #4
               <172> 0x11381431c:    ldr      w17, [x17, x1]
               <176> 0x113814320:    movz     w16, #0x6163
               <180> 0x113814324:    movk     w16, #0x6573, lsl #16 -> 0x65736163
               <184> 0x113814328:    cmp      w17, w16
               <188> 0x11381432c:    b.ne     0x113814444 -> <468>
  11:Term PatternCharacter checked-offset:(4) 'a' already handled
  12:Term PatternCharacter checked-offset:(4) 's' already handled
  13:Term PatternCharacter checked-offset:(4) 'e' already handled
  14:NestedAlternativeNext minimum-size:(5),checked-offset:(5)
               <192> 0x113814330:    movz     x16, #0x4444
               <196> 0x113814334:    movk     x16, #0x1381, lsl #16
               <200> 0x113814338:    movk     x16, #0x8001, lsl #32
               <204> 0x11381433c:    movk     x16, #0xc973, lsl #48 -> 0x113814444 JIT PC
               <208> 0x113814340:    stur     x16, [sp, #8]
               <212> 0x113814344:    b        0x113814404 -> <404>
With some additional backtracking code:
   9:NestedAlternativeNext minimum-size:(4),checked-offset:(4)
               <468> 0x113814444:    sub      w1, w1, #2
               <472> 0x113814448:    b        0x113814348 -> <216>

With this change, the processing of "case" becomes:
   9:StringListAlternativeNext minimum-size:(4),checked-offset:(4)
               <132> 0x12a8285c4:    sub      w1, w1, #1
               <136> 0x12a8285c8:    cmp      w1, w2
               <140> 0x12a8285cc:    b.hi     0x12a8285e8 -> <168>
  10:Term PatternCharacter checked-offset:(4) 'c'
               <144> 0x12a8285d0:    sub      x17, x0, #4
               <148> 0x12a8285d4:    ldr      w17, [x17, x1]
               <152> 0x12a8285d8:    movz     w16, #0x6163
               <156> 0x12a8285dc:    movk     w16, #0x6573, lsl #16 -> 0x65736163
               <160> 0x12a8285e0:    cmp      w17, w16
               <164> 0x12a8285e4:    b.eq     0x12a82866c -> <300>
  11:Term PatternCharacter checked-offset:(4) 'a' already handled
  12:Term PatternCharacter checked-offset:(4) 's' already handled
  13:Term PatternCharacter checked-offset:(4) 'e' already handled
  14:StringListAlternativeNext minimum-size:(5),checked-offset:(5)
With no backtracking code.

We are able to eliminate one branch and the saving of the continuation PC for backtracking.
The code size to process these string list RegExp is reduces.  For the example RegExp above,
the prior version created 1940 bytes (485 instructions) of code while the code created with this
1392 bytes (345 instructions) of code, a nearly 30% reduction in code.

This change is a ~18% progression on the new regexp-keyword-parsing microbenchmark:

                                 Baseline               YarrStringList

regexp-keyword-parsing      136.7065+-0.9807     ^    116.0161+-1.1791        ^ definitely 1.1783x faster

<geometric>                 136.7065+-0.9807     ^    116.0161+-1.1791        ^ definitely 1.1783x faster

* JSTests/microbenchmarks/regexp-keyword-parsing.js: Added.
(arrayToString):
(objectToString):
(dumpValue):
(compareArray):
(compareGroups):
(testRegExp):
(testRegExpSyntaxError):
(let.re.break.case.catch.continue.debugger.default.else.finally.if):
(let.re1.break.case.catch.continue.debugger.default.else.finally.if):
* JSTests/stress/regexp-parsing-tokens.js: Added.
(arrayToString):
(objectToString):
(dumpValue):
(compareArray):
(compareGroups):
(testRegExp):
(testRegExpSyntaxError):
* Source/JavaScriptCore/yarr/YarrJIT.cpp:
* Source/JavaScriptCore/yarr/YarrPattern.cpp:
(JSC::Yarr::YarrPatternConstructor::atomParenthesesEnd):
(JSC::Yarr::YarrPatternConstructor::checkForTerminalParentheses):
(JSC::Yarr::PatternAlternative::dump):
(JSC::Yarr::PatternTerm::dump):
* Source/JavaScriptCore/yarr/YarrPattern.h:
(JSC::Yarr::PatternTerm::PatternTerm):
(JSC::Yarr::PatternAlternative::PatternAlternative):

Canonical link: https://commits.webkit.org/290982@main
pulkomandy pushed a commit that referenced this pull request Jun 20, 2025
https://bugs.webkit.org/show_bug.cgi?id=294344
rdar://153095450

Reviewed by Keith Miller.

Relanding Keith's change with some fixes for x64. In x64, we cannot
directly get label address, so instead of doing it, we store them into
JSCConfig and load it.

This patch hardens how IPInt dispatches opcodes for better CFI protection. Since IPInt does an offset based
dispatch the previous dispatch was something like:

```
macro dispatchToNextIPIntInstruction()
    // x7 is set to _ipInt_instruction_base on entry to IPInt entry/call return.
    loadb [PC], x0
    emit "add x0, x7, x0, lsl #8"
    emit "br x0"
end

align 256
_ipint_dispatch_base:
.first_wasm_bytecode:
// stuff
dispatchToNextIPIntInstruction()

align 256
.second_wasm_bytecode:
// stuff
dispatchToNextIPIntInstruction()
...
align 256
.255_wasm_bytecode:
// stuff
dispatchToNextIPIntInstruction()
```
In the old system no matter what value [PC] points to there are 256 offsets reachable, all of which are
either a valid opcode or a slab of `brk`s.

However, this still means if an attacker is able to return to the IPInt interpreter on some path that
doesn't reset x7 then they'll be able to implement a JOP attack. One example would be to build a fake
object with a vtable pointing to one of the "C function" labels (e.g. _first_wasm_bytecode_validate,
which is used for offset validation).

After this change dispatch is now:

```
macro dispatchToNextIPIntInstruction()
    loadb something, x0
    pcrtoaddr _ipint_dispatch_base, x7
    emit "add x0, x7, x0, lsl #8"
    emit "br x0"
end
```

which makes it clearly impossible to get a PAC bypass in IPInt dispatch. Since there's no longer
a semi-pinned register with the base pointer this patch removes all that associated code.

Additionally, this change adds a names for all the dispatch starts to make the
code a bit easier to read.

Lastly, the SIMD prefix opcode was missing a security guard so this patch adds that too.

* Source/JavaScriptCore/llint/InPlaceInterpreter.asm:
* Source/JavaScriptCore/llint/InPlaceInterpreter.cpp:
(JSC::IPInt::initialize):
* Source/JavaScriptCore/llint/InPlaceInterpreter.h:
* Source/JavaScriptCore/llint/InPlaceInterpreter32_64.asm:
* Source/JavaScriptCore/llint/InPlaceInterpreter64.asm:
* Source/JavaScriptCore/llint/LowLevelInterpreter.asm:
* Source/JavaScriptCore/runtime/JSCConfig.h:

Canonical link: https://commits.webkit.org/296121@main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants