Commit 3b9069ce 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 Filip Pizlo.

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/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/js/SerializedScriptValue.cpp:
(WebCore::CloneSerializer::dumpIfTerminal):
* 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@126494 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent df781cd7
2012-08-23 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 Filip Pizlo.
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-23 Ulan Degenbaev <ulan@chromium.org>
Adjust test expectations for fast/js/toString-overrides.html and fast/js/eval-cross-window.html
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>
......@@ -865,6 +865,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-23 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 Filip Pizlo.
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-23 Mark Rowe <mrowe@apple.com>
Make JavaScriptCore build with the latest version of clang.
......
......@@ -262,6 +262,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;
......
......@@ -618,7 +618,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;
......@@ -650,16 +650,23 @@ bool AbstractState::execute(unsigned indexInBlock)
case IsString:
case IsObject:
case IsFunction: {
node.setCanExit(false);
node.setCanExit(node.op() == IsUndefined && m_codeBlock->globalObjectFor(node.codeOrigin)->masqueradesAsUndefinedWatchpoint()->isStillValid());
JSValue child = forNode(node.child1()).value();
if (child) {
bool constantWasSet;
switch (node.op()) {
case IsUndefined:
constantWasSet = trySetConstant(nodeIndex, jsBoolean(
child.isCell()
? child.asCell()->structure()->typeInfo().masqueradesAsUndefined()
: child.isUndefined()));
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()));
......@@ -739,8 +746,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;
}
......@@ -1077,7 +1084,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(1) : TrustedImm32(0), 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(1) : TrustedImm32(0), 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(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, invert ? notTaken : taken);
}
if (!isKnownCell(operand.index())) {
jump(notTaken, ForceJump);
......@@ -3580,9 +3614,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(1) : TrustedImm32(0), 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(1) : TrustedImm32(0), 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(JITCompiler::Equal, localGlobalObjectGPR, remoteGlobalObjectGPR, invert ? notTaken : taken);
}
if (!isKnownCell(operand.index())) {
jump(notTaken, ForceJump);
......@@ -3553,9 +3587,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(0), 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::<