<html>
    <head>
      <base href="https://bugs.webkit.org/" />
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - JSWrapperMap memory leak"
   href="https://bugs.webkit.org/show_bug.cgi?id=165479">165479</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>JSWrapperMap memory leak
          </td>
        </tr>

        <tr>
          <th>Classification</th>
          <td>Unclassified
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>WebKit
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>Other
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>Unspecified
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Unspecified
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>Normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P2
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>JavaScriptCore
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>webkit-unassigned&#64;lists.webkit.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>daniel.zimmerman&#64;me.com
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Created <span class=""><a href="attachment.cgi?id=296299" name="attach_296299" title="The xcodeproj containing an example set up where this issue occurs">attachment 296299</a> <a href="attachment.cgi?id=296299&amp;action=edit" title="The xcodeproj containing an example set up where this issue occurs">[details]</a></span>
The xcodeproj containing an example set up where this issue occurs

m_cachedObjCWrappers grows without bound. Even though the JSValue are autoreleased, the map continues to grow as if they were still in existence. The issue appears to be with using a weak valued NSMapTable as described here: <a href="http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/">http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/</a>

This issue isn't always reproducible - it appears that theres some sort of timing needed to somehow trick the NSMapTable to not resize at the proper time. I ran the app through the leak instrument and it claimed there were &quot;no leaks&quot; and indeed inspecting the live objects nothing appears to be leaking, but NSMapTable appears to continue to grow without bound for some reason (if you look at the logged `count` then you'll see that the count grows very large and then resets back down to a very small number every time the map table is resized, however this doesn't happen often enough so the map table is forced to grow unnecessarily). This does seem like a map table issue, however I think temporarily a fix can be found for JSC.

My proposed solution is to change `m_cachedObjCWrappers` to a `std::unordered_map&lt;JSValueRef, JSValue*&gt;` or whatever equivalent exists in WTF (I'm not very familiar with WTF) and then create a lightweight objc wrapper around JSValueRef that's then associated with the JSValue* and removes the entry in `m_cachedObjCWrappers` when `-dealloc` is called. E.g. the wrapper would look like

```
&#64;interface JSValueRefCacheClearer : NSObject
- (instancetype)initWithValue:(JSValueRef)value;
&#64;end

&#64;implementation JSValueRefCacheClearer {
  JSValueRef _value;
}
- (instancetype)initWithValue:(JSValueRef)value {
  if ((self = [super init]) != nil) {
    _value = value;
  }
  return self;
}

- (void)dealloc {
  m_cachedObjCWrappers.remove(_value);
  [super dealloc];
}
&#64;end
```

And then `-[JSWrapperMap objcWrapperForJSValueRef:]` would change to
```
- (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value {
  JSValue *wrapper = m_cachedObjCWrappers[value];
  if (!wrapper) {
    wrapper = [[[JSValue alloc] initWithValue:value inContext:m_context] autorelease];
    m_cachedObjCWrappers[value] = wrapper;
    JSValueRefCacheClearer *clearer = [[JSValueRefCacheClearer alloc] initWithValue:value];
    objc_setAssociatedObject(wrapper, static_cast&lt;void *&gt;(clearer), clearer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    // we pass ownership over to the wrapper
    [clearer release];
  }
  return wrapper;
}
```

I'll gladly create the patch myself (following <a href="https://webkit.org/contributing-code/">https://webkit.org/contributing-code/</a>) as long as the bug is accepted as in fact a bug and the proposed change seems reasonable (albeit, it does feel a bit hacky).</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are the assignee for the bug.</li>
      </ul>
    </body>
</html>