-
Notifications
You must be signed in to change notification settings - Fork 859
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed deadlock when sealing objects with a LazyCtor
The reason is that ScriptableObject::sealObject will initialize eagerly any LazyLoadedCtor that are stored in the slot map - it needs to that because some of those will actually mutate the object (such as NativeJavaTopPackage), and that cannot work if the object is already sealed. However, it will also acquire a read lock on the slot map before iterating on it. But the mutations will try to acquire a write lock, causing a deadlock with just one thread. This change fixes it by not holding the read lock while mutating, and also avoids marking the object as sealed until it is certainly correct to do so.
- Loading branch information
1 parent
085d561
commit c6a873f
Showing
2 changed files
with
60 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
testsrc/org/mozilla/javascript/ThreadSafeScriptableObjectTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package org.mozilla.javascript; | ||
|
||
import static org.junit.Assert.assertNotNull; | ||
|
||
import org.junit.Test; | ||
|
||
public class ThreadSafeScriptableObjectTest { | ||
@Test | ||
public void canSealGlobalObjectWithoutDeadlock() { | ||
ContextFactory.getGlobalSetter() | ||
.setContextFactoryGlobal( | ||
new ContextFactory() { | ||
@Override | ||
protected boolean hasFeature(Context cx, int featureIndex) { | ||
if (featureIndex == Context.FEATURE_THREAD_SAFE_OBJECTS) { | ||
return true; | ||
} | ||
return super.hasFeature(cx, featureIndex); | ||
} | ||
}); | ||
|
||
try (Context cx = Context.enter()) { | ||
ScriptableObject global = cx.initStandardObjects(); | ||
global.sealObject(); | ||
|
||
// Registered by NativeJavaTopPackage | ||
assertNotNull(global.get("Packages", global)); | ||
} | ||
} | ||
} |