Bug 236843

Summary: [JSC] ReferenceError when using extra parens in class fields
Product: WebKit Reporter: Liam Mitchell <mitchell.liam>
Component: JavaScriptCoreAssignee: Yusuke Suzuki <ysuzuki>
Status: RESOLVED FIXED    
Severity: Normal CC: ews-watchlist, keith_miller, mark.lam, msaboff, saam, tzagallo, webkit-bug-importer, ysuzuki
Priority: P2 Keywords: InRadar
Version: Safari Technology Preview   
Hardware: Mac (Intel)   
OS: macOS 11   
Attachments:
Description Flags
Two reproducible examples
none
Patch none

Description Liam Mitchell 2022-02-18 09:28:49 PST
Created attachment 452527 [details]
Two reproducible examples

Extra params inside class field declarations cause ReferenceErrors.

Example 1:

;(() => {
  const a = (x) => x
  
  class B {
    c = a(('OK'));
  }

  // Should write 'OK'
  document.write(new B().c)
})()

Throws ReferenceError: Can't find variable: a

Example 2:

;(() => {
  const a = 'OK'

  class B {
    static c = {
      d: a,
      e: (1),
    }
  }

  // Should write 'OK'
  document.write(B.c.d)
})()

Throws ReferenceError: Can't find variable: a

Tested on Safari TP 15.4, Safari 15.2, 15.3, iOS 14.5, 15.0
Comment 1 Liam Mitchell 2022-02-18 21:18:20 PST
This is only reproducible without dev tools. If dev tools is open, the code works as expected.
Comment 2 Radar WebKit Bug Importer 2022-02-23 15:41:02 PST
<rdar://problem/89382583>
Comment 3 Keith Miller 2022-03-04 13:29:30 PST
Hi Liam,

Thanks for the report! Given that it doesn't happen with the DevTools open it sounds like this could be a JIT bug.
Comment 4 Keith Miller 2022-03-04 13:30:25 PST
Actually I'm not so sure it's a JIT bug; you don't have any loops in the code you're running.
Comment 5 Keith Miller 2022-03-04 13:38:21 PST
Looks like we're failing to create a lexical environment when the extra parens are there for some reason...

(function foo() {
  const a = (x) => x

  class B {
//    c = a('OK');
      c = a(('OK'));
  }

  // Should write 'OK'
  print(new B().c)
})()

produces the following byte code:

foo#CMKAuY:[0x1078f4130->0x107871300, NoneFunctionCall, 100]: 25 instructions (0 16-bit instructions, 0 32-bit instructions, 8 instructions with metadata); 216 bytes (116 metadata bytes); 1 parameter(s); 20 callee register(s); 7 variable(s); scope at loc4

bb#1
Predecessors: [ ]
[   0] enter
[   1] get_scope          dst:loc4
[   3] mov                dst:loc5, src:loc4
[   6] check_traps
[   7] mov                dst:loc6, src:callee
[  10] mov                dst:loc7, src:<JSValue()>(const0)
[  13] mov                dst:loc8, src:<JSValue()>(const0)
[  16] new_func_exp       dst:loc7, scope:loc4, functionDecl:0
[  20] mov                dst:loc9, src:<JSValue()>(const0)
[  23] new_func_exp       dst:loc10, scope:loc4, functionDecl:1
[  27] new_object         dst:loc11, inlineCapacity:0
[  31] define_data_property base:loc11, property:String (atomic),8Bit:(1),length:(11): constructor, StructureID: 16608(const1), value:loc10, attributes:Int32: 89(const2)
[  36] define_data_property base:loc10, property:String (atomic),8Bit:(1),length:(9): prototype, StructureID: 16608(const3), value:loc11, attributes:Int32: 74(const4)
[  41] new_func_exp       dst:loc12, scope:loc4, functionDecl:2
[  45] put_by_id          base:loc12, property:0, value:loc11, flags:Strict
[  51] put_by_id          base:loc10, property:1, value:loc12, flags:IsDirect|Strict
[  57] mov                dst:loc9, src:loc10
[  60] mov                dst:loc8, src:loc10
[  63] resolve_scope      dst:loc12, scope:loc4, var:2, resolveType:GlobalProperty, localScopeDepth:0
[  70] get_from_scope     dst:loc9, scope:loc12, var:2, getPutInfo:2048<ThrowIfNotFound|GlobalProperty|NotInitialization|NotStrictMode>, localScopeDepth:0, offset:0
[  78] mov                dst:loc14, src:loc8
[  81] construct          dst:loc13, callee:loc8, argc:1, argv:20
[  87] get_by_id          dst:loc11, base:loc13, property:3
[  92] call               dst:loc9, callee:loc9, argc:2, argv:18
[  98] ret                value:Undefined(const5)
Successors: [ ]

but if the comments are flipped we get:

foo#CpArJP:[0x103ff4130->0x103f71300, NoneFunctionCall, 113]: 27 instructions (0 16-bit instructions, 0 32-bit instructions, 9 instructions with metadata); 229 bytes (116 metadata bytes); 1 parameter(s); 20 callee register(s); 7 variable(s); scope at loc4

bb#1
Predecessors: [ ]
[   0] enter
[   1] get_scope          dst:loc4
[   3] mov                dst:loc5, src:loc4
[   6] check_traps
[   7] mov                dst:loc6, src:callee
[  10] create_lexical_environment dst:loc8, scope:loc4, symbolTable:Cell: 0x104100da8 (0x280004700:[0x4700/18176, SymbolTable, (0/0, 0/0){}, NonArray, Leaf]), StructureID: 18176(const0), initialValue:<JSValue()>(const1)
[  15] mov                dst:loc4, src:loc8
[  18] mov                dst:loc7, src:<JSValue()>(const1)
[  21] new_func_exp       dst:loc9, scope:loc4, functionDecl:0
[  25] put_to_scope       scope:loc8, var:0, value:loc9, getPutInfo:1049604<DoNotThrowIfNotFound|ResolvedClosureVar|ConstInitialization|NotStrictMode>, symbolTableOrScopeDepth:0, offset:0
[  33] mov                dst:loc9, src:<JSValue()>(const1)
[  36] new_func_exp       dst:loc10, scope:loc4, functionDecl:1
[  40] new_object         dst:loc11, inlineCapacity:0
[  44] define_data_property base:loc11, property:String (atomic),8Bit:(1),length:(11): constructor, StructureID: 16608(const2), value:loc10, attributes:Int32: 89(const3)
[  49] define_data_property base:loc10, property:String (atomic),8Bit:(1),length:(9): prototype, StructureID: 16608(const4), value:loc11, attributes:Int32: 74(const5)
[  54] new_func_exp       dst:loc12, scope:loc4, functionDecl:2
[  58] put_by_id          base:loc12, property:1, value:loc11, flags:Strict
[  64] put_by_id          base:loc10, property:2, value:loc12, flags:IsDirect|Strict
[  70] mov                dst:loc9, src:loc10
[  73] mov                dst:loc7, src:loc10
[  76] resolve_scope      dst:loc12, scope:loc4, var:3, resolveType:GlobalProperty, localScopeDepth:1
[  83] get_from_scope     dst:loc9, scope:loc12, var:3, getPutInfo:2048<ThrowIfNotFound|GlobalProperty|NotInitialization|NotStrictMode>, localScopeDepth:1, offset:0
[  91] mov                dst:loc14, src:loc7
[  94] construct          dst:loc13, callee:loc7, argc:1, argv:20
[ 100] get_by_id          dst:loc11, base:loc13, property:4
[ 105] call               dst:loc9, callee:loc9, argc:2, argv:18
[ 111] ret                value:Undefined(const6)
Successors: [ ]
Comment 6 Yusuke Suzuki 2022-03-21 02:37:26 PDT
Created attachment 455222 [details]
Patch
Comment 7 Saam Barati 2022-03-21 12:04:15 PDT
Comment on attachment 455222 [details]
Patch

r=me
Comment 8 EWS 2022-03-21 12:58:29 PDT
Committed r291577 (248677@main): <https://commits.webkit.org/248677@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 455222 [details].