Commit 35d5455b authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com

Change behavior of MasqueradesAsUndefined to better accommodate DFG changes

https://bugs.webkit.org/show_bug.cgi?id=93884

Reviewed by Geoffrey Garen.

Source/JavaScriptCore: 

With some upcoming changes to the DFG to remove uses of ClassInfo, we will be changing the behavior of 
MasqueradesAsUndefined. In order to make this change consistent across all of our execution engines, 
we will make this change to MasqueradesAsUndefined as a separate patch. After this patch, MasqueradesAsUndefined 
objects will only masquerade as undefined in their original context (i.e. their original JSGlobalObject). 
For example, if an object that masquerades as undefined in frame A is passed to frame B, it will not 
masquerade as undefined within frame B, but it will continue to masquerade in frame A.

There are two primary changes that are taking place here. One is to thread the ExecState* through 
JSValue::toBoolean and JSCell::toBoolean so that JSCell::toBoolean can check the object's 
JSGlobalObject to compare it to the lexical JSGlobalObject of the currently running code. If the two 
are distinct, then the object cannot MasqueradeAsUndefined.

The other change is to perform this comparison of JSGlobalObjects everywhere where the MasqueradesAsUndefined
flag in the Structure is checked. For C++ code, this check has been factored into its own function in 
Structure::masqueradesAsUndefined. We only perform this check in the DFG if the current JSGlobalObject has 
had a MasqueradesAsUndefined object allocated within its context. This conditional compilation is managed 
through the use of a WatchpointSet in each JSGlobalObject and alternate create() functions for JS DOM wrappers
that are MasqueradesAsUndefined.

* API/JSValueRef.cpp:
(JSValueToBoolean):
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* bytecode/Watchpoint.h:
(WatchpointSet):
* debugger/DebuggerCallFrame.h:
(JSC::DebuggerCallFrame::callFrame):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGCFGSimplificationPhase.cpp:
(JSC::DFG::CFGSimplificationPhase::run):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::compile):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_is_undefined):
(JSC::JIT::emit_op_jeq_null):
(JSC::JIT::emit_op_jneq_null):
(JSC::JIT::emit_op_eq_null):
(JSC::JIT::emit_op_neq_null):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_is_undefined):
(JSC::JIT::emit_op_jeq_null):
(JSC::JIT::emit_op_jneq_null):
(JSC::JIT::emit_op_eq_null):
(JSC::JIT::emit_op_neq_null):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncFilter):
(JSC::arrayProtoFuncEvery):
(JSC::arrayProtoFuncSome):
* runtime/BooleanConstructor.cpp:
(JSC::constructBoolean):
(JSC::callBooleanConstructor):
* runtime/JSCell.h:
(JSCell):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::JSGlobalObject):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
(JSC::JSGlobalObject::masqueradesAsUndefinedWatchpoint):
* runtime/JSString.h:
(JSC::JSCell::toBoolean):
(JSC::JSValue::toBoolean):
* runtime/JSValue.h:
* runtime/ObjectConstructor.cpp:
(JSC::toPropertyDescriptor):
* runtime/Operations.cpp:
(JSC::jsTypeStringForValue):
(JSC::jsIsObjectType):
* runtime/Operations.h:
(JSC):
(JSC::JSValue::equalSlowCaseInline):
* runtime/RegExpConstructor.cpp:
(JSC::setRegExpConstructorMultiline):
* runtime/RegExpPrototype.cpp:
(JSC::regExpProtoFuncToString):
* runtime/Structure.h:
(Structure):
(JSC::Structure::globalObjectOffset):
(JSC::Structure::masqueradesAsUndefined):
(JSC):

Source/WebCore: 

With some upcoming changes to the DFG to remove uses of ClassInfo, we will be changing the behavior of 
MasqueradesAsUndefined. In order to make this change consistent across all of our execution engines, 
we will make this change to MasqueradesAsUndefined as a separate patch. After this patch, MasqueradesAsUndefined 
objects will only masquerade as undefined in their original context (i.e. their original JSGlobalObject). 
For example, if an object that masquerades as undefined in frame A is passed to frame B, it will not 
masquerade as undefined within frame B, but it will continue to masquerade in frame A.

Test: fast/js/document-all-between-frames.html

All of the changes in WebCore are simply passing the additional ExecState argument to JSValue::toBoolean.

* bindings/js/JSCustomSQLStatementErrorCallback.cpp:
(WebCore::JSSQLStatementErrorCallback::handleEvent):
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::addEventListener):
(WebCore::JSDOMWindow::removeEventListener):
* bindings/js/JSDataViewCustom.cpp:
(WebCore::getDataViewMember):
* bindings/js/JSDeviceMotionEventCustom.cpp:
(WebCore::JSDeviceMotionEvent::initDeviceMotionEvent):
* bindings/js/JSDeviceOrientationEventCustom.cpp:
(WebCore::JSDeviceOrientationEvent::initDeviceOrientationEvent):
* bindings/js/JSDictionary.cpp:
(WebCore::JSDictionary::convertValue):
* bindings/js/JSDirectoryEntryCustom.cpp:
(WebCore::JSDirectoryEntry::getFile):
(WebCore::JSDirectoryEntry::getDirectory):
* bindings/js/JSDirectoryEntrySyncCustom.cpp:
(WebCore::getFlags):
* bindings/js/JSHTMLCanvasElementCustom.cpp:
(WebCore::JSHTMLCanvasElement::getContext):
* bindings/js/JSInspectorFrontendHostCustom.cpp:
(WebCore::populateContextMenuItems):
* bindings/js/JSMessageEventCustom.cpp:
(WebCore::handleInitMessageEvent):
* bindings/js/JSWebGLRenderingContextCustom.cpp:
(WebCore::dataFunctionMatrix):
* bindings/js/JSXMLHttpRequestCustom.cpp:
(WebCore::JSXMLHttpRequest::open):
* bindings/js/JavaScriptCallFrame.cpp:
(WebCore::JavaScriptCallFrame::exec):
(WebCore):
* bindings/js/JavaScriptCallFrame.h:
(JavaScriptCallFrame):
* bindings/js/ScriptDebugServer.cpp:
(WebCore::ScriptDebugServer::hasBreakpoint):
* bindings/scripts/CodeGeneratorJS.pm: Also add the custom create function for MasqueradesAsUndefined JS DOM wrappers.
(GenerateEventListenerCall):
(GenerateHeader):
(JSValueToNative):
* bindings/scripts/test/JS/JSTestEventTarget.cpp:
(WebCore::jsTestEventTargetPrototypeFunctionAddEventListener):
(WebCore::jsTestEventTargetPrototypeFunctionRemoveEventListener):
* bindings/scripts/test/JS/JSTestEventTarget.h:
(WebCore::JSTestEventTarget::create):
* bindings/scripts/test/JS/JSTestObj.cpp:
(WebCore::setJSTestObjCreate):
(WebCore::setJSTestObjReflectedBooleanAttr):
(WebCore::setJSTestObjReflectedCustomBooleanAttr):
(WebCore::jsTestObjPrototypeFunctionAddEventListener):
(WebCore::jsTestObjPrototypeFunctionRemoveEventListener):
* bridge/c/c_utility.cpp:
(JSC::Bindings::convertValueToNPVariant):
* bridge/jni/jni_jsobject.mm:
(JavaJSObject::convertValueToJObject):
* bridge/qt/qt_runtime.cpp:
(JSC::Bindings::convertValueToQVariant):

Source/WebKit/mac: 

With some upcoming changes to the DFG to remove uses of ClassInfo, we will be changing the behavior of 
MasqueradesAsUndefined. In order to make this change consistent across all of our execution engines, 
we will make this change to MasqueradesAsUndefined as a separate patch. After this patch, MasqueradesAsUndefined 
objects will only masquerade as undefined in their original context (i.e. their original JSGlobalObject). 
For example, if an object that masquerades as undefined in frame A is passed to frame B, it will not 
masquerade as undefined within frame B, but it will continue to masquerade in frame A.

* Plugins/Hosted/NetscapePluginInstanceProxy.mm:
(WebKit::NetscapePluginInstanceProxy::addValueToArray): Passing ExecState to toBoolean call.

Source/WebKit2: 

With some upcoming changes to the DFG to remove uses of ClassInfo, we will be changing the behavior of 
MasqueradesAsUndefined. In order to make this change consistent across all of our execution engines, 
we will make this change to MasqueradesAsUndefined as a separate patch. After this patch, MasqueradesAsUndefined 
objects will only masquerade as undefined in their original context (i.e. their original JSGlobalObject). 
For example, if an object that masquerades as undefined in frame A is passed to frame B, it will not 
masquerade as undefined within frame B, but it will continue to masquerade in frame A.

* WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:
(WebKit::NPRuntimeObjectMap::convertJSValueToNPVariant): Passing ExecState to toBoolean call.

LayoutTests: 

Added a test that uses a variety of ways of checking whether something is correctly 
masquerading as undefined (or not) in a subframe.

* fast/js/document-all-between-frames-expected.txt: Added.
* fast/js/document-all-between-frames.html: Added.
* fast/js/resources/document-all-between-frames-subframe.html: Added.
* platform/chromium/TestExpectations: Chromium treats document.all differently, so skip our new test.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@125687 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 87917fe4
2012-08-14 Mark Hahnenberg <mhahnenberg@apple.com>
Change behavior of MasqueradesAsUndefined to better accommodate DFG changes
https://bugs.webkit.org/show_bug.cgi?id=93884
Reviewed by Geoffrey Garen.
Added a test that uses a variety of ways of checking whether something is correctly
masquerading as undefined (or not) in a subframe.
* fast/js/document-all-between-frames-expected.txt: Added.
* fast/js/document-all-between-frames.html: Added.
* fast/js/resources/document-all-between-frames-subframe.html: Added.
* platform/chromium/TestExpectations: Chromium treats document.all differently, so skip our new test.
2012-08-15 Adam Barth <abarth@webkit.org>
Update TestExpectations entry to refer to an actual bug.
This diff is collapsed.
<!DOCTYPE HTML>
<html>
<head>
<script src="resources/js-test-pre.js"></script>
</head>
<body>
<script>
window.passUp = null;
</script>
<iframe id="subframe" src="resources/document-all-between-frames-subframe.html"></iframe>
<script>
window.jsTestIsAsync = true;
window.passUp = [];
function waitForResponse() {
if (window.passUp.length < (9 * 300) + 1) {
setTimeout(waitForResponse, 100);
return;
}
for (var i = 0; i < window.passUp.length; i++) {
debug(window.passUp[i]);
}
if (testRunner) {
testRunner.notifyDone();
}
}
var subframe = document.getElementById("subframe");
subframe.contentWindow.passDown = document.all;
if (document.all) {
debug("FAIL: document.all didn't masquerade as undefined");
} else {
debug("document.all masqueraded as undefined");
}
setTimeout(waitForResponse, 100);
</script>
<script src="resources/js-test-post.js"></script>
</body>
</html>
<!DOCTYPE HTML>
<html>
<head>
<title>Subframe</title>
<script src="resources/js-test-pre.js"></script>
</head>
<body>
<script>
var documentDotAll = window.passDown;
window.parent.passUp = [];
if (document.all) {
window.parent.passUp.push("FAIL: if (document.all) didn't masqueraded as undefined");
} else {
window.parent.passUp.push("if (document.all) masqueraded as undefined");
}
for (var i = 0; i < 300; i++) {
if (documentDotAll) {
window.parent.passUp.push("if (documentDotAll) did not masquerade as undefined");
} else {
window.parent.passUp.push("FAIL: if (documentDotAll) masqueraded as undefined");
}
if (documentDotAll == null) {
window.parent.passUp.push("FAIL: if (documentDotAll == null) masqueraded as undefined");
} else {
window.parent.passUp.push("if (documentDotAll == null) did not masquerade as undefined");
}
if (documentDotAll == undefined) {
window.parent.passUp.push("FAIL: if (documentDotAll == undefined) masqueraded as undefined");
} else {
window.parent.passUp.push("if (documentDotAll == undefined) did not masquerade as undefined");
}
if (!documentDotAll) {
window.parent.passUp.push("FAIL: if (!documentDotAll) masqueraded as undefined");
} else {
window.parent.passUp.push("if (!documentDotAll) did not masquerade as undefined");
}
if (documentDotAll != null) {
window.parent.passUp.push("if (documentDotAll != null) did not masquerade as undefined");
} else {
window.parent.passUp.push("FAIL: if (documentDotAll != null) masqueraded as undefined");
}
if (documentDotAll != undefined) {
window.parent.passUp.push("if (documentDotAll != undefined) did not masquerade as undefined");
} else {
window.parent.passUp.push("FAIL: if (documentDotAll != undefined) masqueraded as undefined");
}
if (documentDotAll === undefined) {
window.parent.passUp.push("FAIL: if (documentDotAll === undefined) masqueraded as undefined");
} else {
window.parent.passUp.push("if (documentDotAll === undefined) did not masquerade as undefined");
}
if (documentDotAll !== undefined) {
window.parent.passUp.push("if (documentDotAll !== undefined) did not masquerade as undefined");
} else {
window.parent.passUp.push("FAIL: if (documentDotAll !== undefined) masqueraded as undefined");
}
if (typeof documentDotAll === "undefined") {
window.parent.passUp.push("FAIL: if (typeof documentDotAll === \"undefined\") masqueraded as undefined");
} else {
window.parent.passUp.push("if (typeof documentDotAll === \"undefined\") did not masquerade as undefined");
}
}
</script>
</body>
</html>
......@@ -855,6 +855,9 @@ WONTFIX SKIP : platform/blackberry = PASS
// JavaScriptCore bindings willfully have different behavior than V8 bindings
WONTFIX SKIP : plugins/npruntime/overrides-all-properties.html = TEXT
// JavaScriptCore treats document.all differently
WONTFIX SKIP : fast/js/document-all-between-frames.html = TEXT
// Chromium doesn't use fullscreen-specific media controls
WONTFIX SKIP : media/video-controls-fullscreen-volume.html = TEXT
......
......@@ -266,7 +266,7 @@ bool JSValueToBoolean(JSContextRef ctx, JSValueRef value)
APIEntryShim entryShim(exec);
JSValue jsValue = toJS(exec, value);
return jsValue.toBoolean();
return jsValue.toBoolean(exec);
}
double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
......
2012-08-14 Mark Hahnenberg <mhahnenberg@apple.com>
Change behavior of MasqueradesAsUndefined to better accommodate DFG changes
https://bugs.webkit.org/show_bug.cgi?id=93884
Reviewed by Geoffrey Garen.
With some upcoming changes to the DFG to remove uses of ClassInfo, we will be changing the behavior of
MasqueradesAsUndefined. In order to make this change consistent across all of our execution engines,
we will make this change to MasqueradesAsUndefined as a separate patch. After this patch, MasqueradesAsUndefined
objects will only masquerade as undefined in their original context (i.e. their original JSGlobalObject).
For example, if an object that masquerades as undefined in frame A is passed to frame B, it will not
masquerade as undefined within frame B, but it will continue to masquerade in frame A.
There are two primary changes that are taking place here. One is to thread the ExecState* through
JSValue::toBoolean and JSCell::toBoolean so that JSCell::toBoolean can check the object's
JSGlobalObject to compare it to the lexical JSGlobalObject of the currently running code. If the two
are distinct, then the object cannot MasqueradeAsUndefined.
The other change is to perform this comparison of JSGlobalObjects everywhere where the MasqueradesAsUndefined
flag in the Structure is checked. For C++ code, this check has been factored into its own function in
Structure::masqueradesAsUndefined. We only perform this check in the DFG if the current JSGlobalObject has
had a MasqueradesAsUndefined object allocated within its context. This conditional compilation is managed
through the use of a WatchpointSet in each JSGlobalObject and alternate create() functions for JS DOM wrappers
that are MasqueradesAsUndefined.
* API/JSValueRef.cpp:
(JSValueToBoolean):
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* bytecode/Watchpoint.h:
(WatchpointSet):
* debugger/DebuggerCallFrame.h:
(JSC::DebuggerCallFrame::callFrame):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGCFGSimplificationPhase.cpp:
(JSC::DFG::CFGSimplificationPhase::run):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::compile):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_is_undefined):
(JSC::JIT::emit_op_jeq_null):
(JSC::JIT::emit_op_jneq_null):
(JSC::JIT::emit_op_eq_null):
(JSC::JIT::emit_op_neq_null):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_is_undefined):
(JSC::JIT::emit_op_jeq_null):
(JSC::JIT::emit_op_jneq_null):
(JSC::JIT::emit_op_eq_null):
(JSC::JIT::emit_op_neq_null):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncFilter):
(JSC::arrayProtoFuncEvery):
(JSC::arrayProtoFuncSome):
* runtime/BooleanConstructor.cpp:
(JSC::constructBoolean):
(JSC::callBooleanConstructor):
* runtime/JSCell.h:
(JSCell):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::JSGlobalObject):
* runtime/JSGlobalObject.h:
(JSGlobalObject):
(JSC::JSGlobalObject::masqueradesAsUndefinedWatchpoint):
* runtime/JSString.h:
(JSC::JSCell::toBoolean):
(JSC::JSValue::toBoolean):
* runtime/JSValue.h:
* runtime/ObjectConstructor.cpp:
(JSC::toPropertyDescriptor):
* runtime/Operations.cpp:
(JSC::jsTypeStringForValue):
(JSC::jsIsObjectType):
* runtime/Operations.h:
(JSC):
(JSC::JSValue::equalSlowCaseInline):
* runtime/RegExpConstructor.cpp:
(JSC::setRegExpConstructorMultiline):
* runtime/RegExpPrototype.cpp:
(JSC::regExpProtoFuncToString):
* runtime/Structure.h:
(Structure):
(JSC::Structure::globalObjectOffset):
(JSC::Structure::masqueradesAsUndefined):
(JSC):
2012-08-14 Filip Pizlo <fpizlo@apple.com>
Unreviewed, build fix for !ENABLE(DFG_JIT)
......
......@@ -258,6 +258,7 @@ EXPORTS
?neuter@ArrayBufferView@WTF@@MAEXXZ
?newUninitialized@CString@WTF@@SA?AV12@IAAPAD@Z
?notifyWriteSlow@SymbolTableEntry@JSC@@AAEXXZ
?notifyWriteSlow@WatchpointSet@JSC@@QAEXXZ
?nullptr@@3Vnullptr_t@std@@A
?number@String@WTF@@SA?AV12@NII@Z
?number@UString@JSC@@SA?AV12@H@Z
......
......@@ -78,7 +78,7 @@ public:
bool* addressOfIsWatched() { return &m_isWatched; }
void notifyWriteSlow(); // Call only if you've checked isWatched.
JS_EXPORT_PRIVATE void notifyWriteSlow(); // Call only if you've checked isWatched.
private:
void fireAllWatchpoints();
......
......@@ -48,6 +48,7 @@ namespace JSC {
{
}
CallFrame* callFrame() const { return m_callFrame; }
JSGlobalObject* dynamicGlobalObject() const { return m_callFrame->dynamicGlobalObject(); }
ScopeChainNode* scopeChain() const { return m_callFrame->scopeChain(); }
JS_EXPORT_PRIVATE const UString* functionName() const;
......
......@@ -608,7 +608,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case LogicalNot: {
JSValue childConst = forNode(node.child1()).value();
if (childConst && trySetConstant(nodeIndex, jsBoolean(!childConst.toBoolean()))) {
if (childConst && trySetConstant(nodeIndex, jsBoolean(!childConst.toBoolean(m_codeBlock->globalObjectFor(node.codeOrigin)->globalExec())))) {
m_foundConstants = true;
node.setCanExit(false);
break;
......@@ -646,10 +646,18 @@ bool AbstractState::execute(unsigned indexInBlock)
bool constantWasSet;
switch (node.op()) {
case IsUndefined:
constantWasSet = trySetConstant(nodeIndex, jsBoolean(
child.isCell()
? child.asCell()->structure()->typeInfo().masqueradesAsUndefined()
: child.isUndefined()));
node.setCanExit(true);
if (m_codeBlock->globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
constantWasSet = trySetConstant(nodeIndex, jsBoolean(
child.isCell()
? false
: child.isUndefined()));
} else {
constantWasSet = trySetConstant(nodeIndex, jsBoolean(
child.isCell()
? child.asCell()->structure()->masqueradesAsUndefined(m_codeBlock->globalObjectFor(node.codeOrigin))
: child.isUndefined()));
}
break;
case IsBoolean:
constantWasSet = trySetConstant(nodeIndex, jsBoolean(child.isBoolean()));
......@@ -729,8 +737,8 @@ bool AbstractState::execute(unsigned indexInBlock)
&& m_graph.valueOfJSConstant(node.child1().index()).isNull())
|| (m_graph.isConstant(node.child2().index())
&& m_graph.valueOfJSConstant(node.child2().index()).isNull())) {
// We know that this won't clobber the world. But that's all we know.
node.setCanExit(false);
// We can exit if we haven't fired the MasqueradesAsUndefind watchpoint yet.
node.setCanExit(m_codeBlock->globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid());
break;
}
......@@ -1083,7 +1091,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case Branch: {
JSValue value = forNode(node.child1()).value();
if (value) {
bool booleanValue = value.toBoolean();
bool booleanValue = value.toBoolean(m_codeBlock->globalObjectFor(node.codeOrigin)->globalExec());
if (booleanValue)
m_branchDirection = TakeTrue;
else
......
......@@ -101,7 +101,7 @@ public:
// Branch on constant -> jettison the not-taken block and merge.
if (m_graph[m_graph[block->last()].child1()].hasConstant()) {
bool condition =
m_graph.valueOfJSConstant(m_graph[block->last()].child1().index()).toBoolean();
m_graph.valueOfJSConstant(m_graph[block->last()].child1().index()).toBoolean(m_graph.globalObjectFor(m_graph[block->last()].codeOrigin)->globalExec());
BasicBlock* targetBlock = m_graph.m_blocks[
m_graph.successorForCondition(block, condition)].get();
if (targetBlock->m_predecessors.size() == 1) {
......
......@@ -1273,9 +1273,9 @@ JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState* exec, JSCell* fu
return function;
}
size_t DFG_OPERATION operationIsObject(EncodedJSValue value)
size_t DFG_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value)
{
return jsIsObjectType(JSValue::decode(value));
return jsIsObjectType(exec, JSValue::decode(value));
}
size_t DFG_OPERATION operationIsFunction(EncodedJSValue value)
......@@ -1368,7 +1368,7 @@ size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
return JSValue::decode(encodedOp).toBoolean();
return JSValue::decode(encodedOp).toBoolean(exec);
}
#if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE)
......
......@@ -180,7 +180,7 @@ EncodedJSValue DFG_OPERATION operationGetArgumentByVal(ExecState*, int32_t, int3
JSCell* DFG_OPERATION operationNewFunction(ExecState*, JSCell*) WTF_INTERNAL;
JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState*, JSCell*) WTF_INTERNAL;
double DFG_OPERATION operationFModOnInts(int32_t, int32_t) WTF_INTERNAL;
size_t DFG_OPERATION operationIsObject(EncodedJSValue) WTF_INTERNAL;
size_t DFG_OPERATION operationIsObject(ExecState*, EncodedJSValue) WTF_INTERNAL;
size_t DFG_OPERATION operationIsFunction(EncodedJSValue) WTF_INTERNAL;
void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState*, JSObject*, Structure*, PropertyOffset, EncodedJSValue) WTF_INTERNAL;
char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState*) WTF_INTERNAL;
......
......@@ -623,10 +623,29 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv
JITCompiler::Jump notCell;
if (!isKnownCell(operand.index()))
notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureOffset()), resultPayloadGPR);
m_jit.test8(invert ? JITCompiler::Zero : JITCompiler::NonZero, JITCompiler::Address(resultPayloadGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined), resultPayloadGPR);
JITCompiler::Jump notMasqueradesAsUndefined;
if (m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
m_jit.move(invert ? TrustedImm32(0) : TrustedImm32(1), resultPayloadGPR);
notMasqueradesAsUndefined = m_jit.jump();
} else {
m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureOffset()), resultPayloadGPR);
JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(JITCompiler::NonZero, JITCompiler::Address(resultPayloadGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined));
m_jit.move(invert ? TrustedImm32(0) : TrustedImm32(1), resultPayloadGPR);
notMasqueradesAsUndefined = m_jit.jump();
isMasqueradesAsUndefined.link(&m_jit);
GPRTemporary localGlobalObject(this);
GPRTemporary remoteGlobalObject(this);
GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
m_jit.move(JITCompiler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)), localGlobalObjectGPR);
m_jit.loadPtr(JITCompiler::Address(resultPayloadGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
m_jit.compare32(invert ? JITCompiler::NotEqual : JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, resultPayloadGPR);
}
if (!isKnownCell(operand.index())) {
JITCompiler::Jump done = m_jit.jump();
......@@ -640,6 +659,8 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv
done.link(&m_jit);
}
notMasqueradesAsUndefined.link(&m_jit);
booleanResult(resultPayloadGPR, m_compileIndex);
}
......@@ -668,9 +689,22 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, NodeIndex br
if (!isKnownCell(operand.index()))
notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureOffset()), resultGPR);
branchTest8(invert ? JITCompiler::Zero : JITCompiler::NonZero, JITCompiler::Address(resultGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined), taken);
if (m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
jump(invert ? taken : notTaken, ForceJump);
} else {
m_jit.loadPtr(JITCompiler::Address(argPayloadGPR, JSCell::structureOffset()), resultGPR);
branchTest8(JITCompiler::Zero, JITCompiler::Address(resultGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined), invert ? taken : notTaken);
GPRTemporary localGlobalObject(this);
GPRTemporary remoteGlobalObject(this);
GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
m_jit.move(TrustedImmPtr(m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)), localGlobalObjectGPR);
m_jit.loadPtr(JITCompiler::Address(resultGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
branchPtr(invert ? JITCompiler::NotEqual : JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, taken);
}
if (!isKnownCell(operand.index())) {
jump(notTaken, ForceJump);
......@@ -3768,9 +3802,28 @@ void SpeculativeJIT::compile(Node& node)
JITCompiler::Jump done = m_jit.jump();
isCell.link(&m_jit);
m_jit.loadPtr(JITCompiler::Address(value.payloadGPR(), JSCell::structureOffset()), result.gpr());
m_jit.test8(JITCompiler::NonZero, JITCompiler::Address(result.gpr(), Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), result.gpr());
JITCompiler::Jump notMasqueradesAsUndefined;
if (m_jit.graph().globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
m_jit.move(TrustedImm32(0), result.gpr());
notMasqueradesAsUndefined = m_jit.jump();
} else {
m_jit.loadPtr(JITCompiler::Address(value.payloadGPR(), JSCell::structureOffset()), result.gpr());
JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(JITCompiler::NonZero, JITCompiler::Address(result.gpr(), Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined));
m_jit.move(TrustedImm32(0), result.gpr());
notMasqueradesAsUndefined = m_jit.jump();
isMasqueradesAsUndefined.link(&m_jit);
GPRTemporary localGlobalObject(this);
GPRTemporary remoteGlobalObject(this);
GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
m_jit.move(TrustedImmPtr(m_jit.globalObjectFor(node.codeOrigin)), localGlobalObjectGPR);
m_jit.loadPtr(JITCompiler::Address(result.gpr(), Structure::globalObjectOffset()), remoteGlobalObjectGPR);
m_jit.compare32(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, result.gpr());
}
notMasqueradesAsUndefined.link(&m_jit);
done.link(&m_jit);
booleanResult(result.gpr(), m_compileIndex);
break;
......
......@@ -588,10 +588,29 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv
if (!isKnownCell(operand.index()))
notCell = m_jit.branchTestPtr(MacroAssembler::NonZero, argGPR, GPRInfo::tagMaskRegister);
m_jit.loadPtr(JITCompiler::Address(argGPR, JSCell::structureOffset()), resultGPR);
m_jit.test8(invert ? JITCompiler::Zero : JITCompiler::NonZero, JITCompiler::Address(resultGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined), resultGPR);
JITCompiler::Jump notMasqueradesAsUndefined;
if (m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
m_jit.move(invert ? TrustedImm32(0) : TrustedImm32(1), resultGPR);
notMasqueradesAsUndefined = m_jit.jump();
} else {
m_jit.loadPtr(JITCompiler::Address(argGPR, JSCell::structureOffset()), resultGPR);
JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(JITCompiler::NonZero, JITCompiler::Address(resultGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined));
m_jit.move(invert ? TrustedImm32(0) : TrustedImm32(1), resultGPR);
notMasqueradesAsUndefined = m_jit.jump();
isMasqueradesAsUndefined.link(&m_jit);
GPRTemporary localGlobalObject(this);
GPRTemporary remoteGlobalObject(this);
GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
m_jit.move(JITCompiler::TrustedImmPtr(m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)), localGlobalObjectGPR);
m_jit.loadPtr(JITCompiler::Address(resultGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
m_jit.comparePtr(invert ? JITCompiler::NotEqual : JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, resultGPR);
}
if (!isKnownCell(operand.index())) {
JITCompiler::Jump done = m_jit.jump();
......@@ -603,7 +622,9 @@ void SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull(Edge operand, bool inv
done.link(&m_jit);
}
notMasqueradesAsUndefined.link(&m_jit);
m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean);
}
......@@ -632,9 +653,22 @@ void SpeculativeJIT::nonSpeculativePeepholeBranchNull(Edge operand, NodeIndex br
if (!isKnownCell(operand.index()))
notCell = m_jit.branchTestPtr(MacroAssembler::NonZero, argGPR, GPRInfo::tagMaskRegister);
m_jit.loadPtr(JITCompiler::Address(argGPR, JSCell::structureOffset()), resultGPR);
branchTest8(invert ? JITCompiler::Zero : JITCompiler::NonZero, JITCompiler::Address(resultGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined), taken);
if (m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
jump(invert ? taken : notTaken, ForceJump);
} else {
m_jit.loadPtr(JITCompiler::Address(argGPR, JSCell::structureOffset()), resultGPR);
branchTest8(JITCompiler::Zero, JITCompiler::Address(resultGPR, Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(MasqueradesAsUndefined), invert ? taken : notTaken);
GPRTemporary localGlobalObject(this);
GPRTemporary remoteGlobalObject(this);
GPRReg localGlobalObjectGPR = localGlobalObject.gpr();
GPRReg remoteGlobalObjectGPR = remoteGlobalObject.gpr();
m_jit.move(TrustedImmPtr(m_jit.graph().globalObjectFor(m_jit.graph()[operand].codeOrigin)), localGlobalObjectGPR);
m_jit.loadPtr(JITCompiler::Address(resultGPR, Structure::globalObjectOffset()), remoteGlobalObjectGPR);
branchPtr(invert ? JITCompiler::NotEqual : JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, taken);
}
if (!isKnownCell(operand.index())) {
jump(notTaken, ForceJump);
......@@ -3755,9 +3789,28 @@ void SpeculativeJIT::compile(Node& node)
JITCompiler::Jump done = m_jit.jump();
isCell.link(&m_jit);
m_jit.loadPtr(JITCompiler::Address(value.gpr(), JSCell::structureOffset()), result.gpr());
m_jit.test8(JITCompiler::NonZero, JITCompiler::Address(result.gpr(), Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), result.gpr());
JITCompiler::Jump notMasqueradesAsUndefined;
if (m_jit.graph().globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid()) {
m_jit.graph().globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->add(speculationWatchpoint());
m_jit.move(TrustedImm32(ValueFalse), result.gpr());
notMasqueradesAsUndefined = m_jit.jump();
} else {
m_jit.loadPtr(JITCompiler::Address(value.gpr(), JSCell::structureOffset()), result.gpr());
JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(JITCompiler::NonZero, JITCompiler::Address(result.gpr(), Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined));
m_jit.move(TrustedImm32(ValueFalse), result.gpr());
notMasqueradesAsUndefined = m_jit.jump();
isMasqueradesAsUndefined.link(&m_jit);
GPRTemporary localGlobalObject(this);