Diff
Modified: trunk/JSTests/ChangeLog (206845 => 206846)
--- trunk/JSTests/ChangeLog 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/JSTests/ChangeLog 2016-10-06 05:20:10 UTC (rev 206846)
@@ -1,3 +1,23 @@
+2016-10-05 Yusuke Suzuki <[email protected]>
+
+ [DOMJIT] Add initial CheckDOM and CallDOM implementations
+ https://bugs.webkit.org/show_bug.cgi?id=162941
+
+ Reviewed by Filip Pizlo.
+
+ * stress/domjit-getter-poly.js: Added.
+ (shouldBe):
+ (access):
+ * stress/domjit-getter-proto.js: Added.
+ (shouldBe):
+ (access):
+ * stress/domjit-getter-super-poly.js: Added.
+ (shouldBe):
+ (access):
+ * stress/domjit-getter.js: Added.
+ (shouldBe):
+ (access):
+
2016-10-04 Saam Barati <[email protected]>
String.prototype.toLowerCase should be a DFG/FTL intrinsic
Added: trunk/JSTests/stress/domjit-getter-poly.js (0 => 206846)
--- trunk/JSTests/stress/domjit-getter-poly.js (rev 0)
+++ trunk/JSTests/stress/domjit-getter-poly.js 2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`bad value: ${String(actual)}`);
+}
+
+var domjit1 = createDOMJITGetterObject();
+var domjit2 = createDOMJITGetterObject();
+
+function access(domjit)
+{
+ return domjit.customGetter + domjit.customGetter;
+}
+
+for (var i = 0; i < 1e4; ++i)
+ shouldBe(access((i & 0x1) ? domjit1 : domjit2), 84);
+
+shouldBe(access({ customGetter: 42 }), 84);
+domjit1.test = 44;
+shouldBe(access(domjit1), 84);
Added: trunk/JSTests/stress/domjit-getter-proto.js (0 => 206846)
--- trunk/JSTests/stress/domjit-getter-proto.js (rev 0)
+++ trunk/JSTests/stress/domjit-getter-proto.js 2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,17 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`bad value: ${String(actual)}`);
+}
+
+var domjit = createDOMJITNodeObject();
+function access(domjit)
+{
+ return domjit.customGetter + domjit.customGetter;
+}
+
+for (var i = 0; i < 1e4; ++i)
+ shouldBe(access(domjit), 84);
+
+shouldBe(access({ customGetter: 42 }), 84);
+domjit.test = 44;
+shouldBe(access(domjit), 84);
Added: trunk/JSTests/stress/domjit-getter-super-poly.js (0 => 206846)
--- trunk/JSTests/stress/domjit-getter-super-poly.js (rev 0)
+++ trunk/JSTests/stress/domjit-getter-super-poly.js 2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`bad value: ${String(actual)}`);
+}
+
+var domjits = [];
+for (var i = 0; i < 100; ++i)
+ domjits.push(createDOMJITGetterObject());
+
+function access(domjit)
+{
+ return domjit.customGetter + domjit.customGetter;
+}
+
+for (var i = 0; i < 1e2; ++i) {
+ for (var j = 0; j < domjits.length; ++j)
+ shouldBe(access(domjits[j]), 84);
+}
Added: trunk/JSTests/stress/domjit-getter.js (0 => 206846)
--- trunk/JSTests/stress/domjit-getter.js (rev 0)
+++ trunk/JSTests/stress/domjit-getter.js 2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error(`bad value: ${String(actual)}`);
+}
+
+var domjit = createDOMJITGetterObject();
+
+function access(domjit)
+{
+ return domjit.customGetter + domjit.customGetter;
+}
+
+for (var i = 0; i < 1e4; ++i)
+ shouldBe(access(domjit), 84);
+
+shouldBe(access({ customGetter: 42 }), 84);
+domjit.test = 44;
+shouldBe(access(domjit), 84);
Modified: trunk/Source/_javascript_Core/ChangeLog (206845 => 206846)
--- trunk/Source/_javascript_Core/ChangeLog 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-10-06 05:20:10 UTC (rev 206846)
@@ -1,5 +1,150 @@
2016-10-05 Yusuke Suzuki <[email protected]>
+ [DOMJIT] Add initial CheckDOM and CallDOM implementations
+ https://bugs.webkit.org/show_bug.cgi?id=162941
+
+ Reviewed by Filip Pizlo.
+
+ This patch implements a prototype of DOMJIT accelerated getter.
+ We add two new DFG nodes, CheckDOM and CallDOM.
+
+ CheckDOM is used to filter inappropriate |this| object for DOM getter. Its functionality
+ is equivalent to jsDynamicCast's Check. You can use like "CheckDOM, @1, JSNode::info()",
+ and this CheckDOM incurs a BadType exit if the class of the given @1 is not a subclass of
+ JSNode::info().
+
+ CallDOM is used to emit actual DOM operations. It takes GlobalObject and checked DOM
+ object. And it returns JSValue as its result.
+
+ Both CheckDOM and CallDOM can take a DOMJIT::Patchpoint. This is somewhat code snippet
+ generator, and is injectable to DFG and FTL. DFG and FTL set up registers correctly
+ according to DOMJIT::Patchpoint's requirement and invoke this patchpoint generator to emit code.
+ While CallDOM always requires a patchpoint, ideally CheckDOM does not require it since
+ isSubclassOf check can be implemented in DFG / FTL side. However, some classes have a
+ faster way to query isSubclassOf. For example, JSNode in WebCore introduces a special
+ JSType to optimize this query. CheckDOM's patchpoint gives us a chance to emit special
+ faster code for such a case.
+
+ By leveraging above nodes, we can construct DOMJIT accelerated getter. When DFG recognizes the
+ given getter call is CustomGetter and it has DOMJIT::GetterSetter information, DFG emits the above nodes.
+ We implemented a prototype in jsc.cpp shell as DOMJITGetter to test the functionality.
+
+ Notes about the future extensions.
+
+ 1. Currently, we do not allow CallDOM to emit any function calls. This will be extended by
+ adding `addSlowPathCall` functionality to DOMJIT::Patchpoint later. Interesting thing is that
+ we need to create an abstraction over DFG slow path call and FTL slow path call!
+
+ 2. CheckDOM is not handled in DFGTypeCheckHoistingPhase yet. And we have a chance to merge several CheckDOM into one.
+ For example, given CheckDOM A and CheckDOM B to the same target. If A is subclass of B, we can merge them to CheckDOM A.
+
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * b3/B3Effects.h:
+ (JSC::B3::Effects::forCheck):
+ * b3/B3Value.cpp:
+ (JSC::B3::Value::effects):
+ * bytecode/GetByIdStatus.cpp:
+ (JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
+ (JSC::GetByIdStatus::makesCalls):
+ (JSC::GetByIdStatus::dump):
+ * bytecode/GetByIdStatus.h:
+ (JSC::GetByIdStatus::GetByIdStatus):
+ (JSC::GetByIdStatus::isCustom):
+ (JSC::GetByIdStatus::takesSlowPath):
+ (JSC::GetByIdStatus::isSimple): Deleted.
+ * bytecode/SpeculatedType.cpp:
+ (JSC::speculationFromClassInfo):
+ * dfg/DFGAbstractInterpreter.h:
+ (JSC::DFG::AbstractInterpreter::filterClassInfo):
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::filterClassInfo):
+ * dfg/DFGAbstractValue.cpp:
+ (JSC::DFG::AbstractValue::filterClassInfo):
+ * dfg/DFGAbstractValue.h:
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleDOMJITGetter):
+ (JSC::DFG::ByteCodeParser::handleGetById):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasHeapPrediction):
+ (JSC::DFG::Node::hasDOMJIT):
+ (JSC::DFG::Node::domJIT):
+ (JSC::DFG::Node::hasClassInfo):
+ (JSC::DFG::Node::classInfo):
+ (JSC::DFG::Node::OpInfoWrapper::OpInfoWrapper):
+ (JSC::DFG::Node::OpInfoWrapper::operator=):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGOpInfo.h:
+ (JSC::DFG::OpInfo::OpInfo):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::allocateTemporaryRegistersForPatchpoint):
+ (JSC::DFG::SpeculativeJIT::compileCallDOM):
+ (JSC::DFG::SpeculativeJIT::compileCheckDOM):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGStructureAbstractValue.cpp:
+ (JSC::DFG::StructureAbstractValue::filterClassInfoSlow):
+ (JSC::DFG::StructureAbstractValue::isSubClassOf):
+ * dfg/DFGStructureAbstractValue.h:
+ (JSC::DFG::StructureAbstractValue::filterClassInfo):
+ (JSC::DFG::StructureAbstractValue::filter): Deleted.
+ * domjit/DOMJITPatchpointParams.h: Copied from Source/_javascript_Core/dfg/DFGOpInfo.h.
+ (JSC::DOMJIT::PatchpointParams::~PatchpointParams):
+ (JSC::DOMJIT::PatchpointParams::size):
+ (JSC::DOMJIT::PatchpointParams::at):
+ (JSC::DOMJIT::PatchpointParams::operator[]):
+ (JSC::DOMJIT::PatchpointParams::gpScratch):
+ (JSC::DOMJIT::PatchpointParams::fpScratch):
+ (JSC::DOMJIT::PatchpointParams::PatchpointParams):
+ * domjit/DOMJITReg.h: Added.
+ (JSC::DOMJIT::Reg::Reg):
+ (JSC::DOMJIT::Reg::isGPR):
+ (JSC::DOMJIT::Reg::isFPR):
+ (JSC::DOMJIT::Reg::isJSValueRegs):
+ (JSC::DOMJIT::Reg::gpr):
+ (JSC::DOMJIT::Reg::fpr):
+ (JSC::DOMJIT::Reg::jsValueRegs):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileCheckDOM):
+ (JSC::FTL::DFG::LowerDFGToB3::compileCallDOM):
+ (JSC::FTL::DFG::LowerDFGToB3::compileUnreachable): Deleted.
+ * jit/AssemblyHelpers.h:
+ * jsc.cpp:
+ (WTF::DOMJITNode::DOMJITNode):
+ (WTF::DOMJITNode::createStructure):
+ (WTF::DOMJITNode::create):
+ (WTF::DOMJITNode::value):
+ (WTF::DOMJITNode::offsetOfValue):
+ (WTF::DOMJITGetter::DOMJITGetter):
+ (WTF::DOMJITGetter::createStructure):
+ (WTF::DOMJITGetter::create):
+ (WTF::DOMJITGetter::DOMJITNodeDOMJIT::DOMJITNodeDOMJIT):
+ (WTF::DOMJITGetter::domJITNodeGetterSetter):
+ (WTF::DOMJITGetter::finishCreation):
+ (WTF::DOMJITGetter::customGetter):
+ (GlobalObject::finishCreation):
+ (functionCreateDOMJITNodeObject):
+ (functionCreateDOMJITGetterObject):
+
+2016-10-05 Yusuke Suzuki <[email protected]>
+
[JSC] Do not construct Simple GetByIdStatus against self-custom-accessor case
https://bugs.webkit.org/show_bug.cgi?id=162993
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (206845 => 206846)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2016-10-06 05:20:10 UTC (rev 206846)
@@ -2098,6 +2098,8 @@
E35E03601B7AB43E0073AD2A /* InspectorInstrumentationObject.h in Headers */ = {isa = PBXBuildFile; fileRef = E35E035E1B7AB43E0073AD2A /* InspectorInstrumentationObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
E3794E751B77EB97005543AE /* ModuleAnalyzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3794E731B77EB97005543AE /* ModuleAnalyzer.cpp */; };
E3794E761B77EB97005543AE /* ModuleAnalyzer.h in Headers */ = {isa = PBXBuildFile; fileRef = E3794E741B77EB97005543AE /* ModuleAnalyzer.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ E37AD83C1DA4928600F3D412 /* DOMJITPatchpointParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ E37AD83D1DA4928600F3D412 /* DOMJITReg.h in Headers */ = {isa = PBXBuildFile; fileRef = E37AD83B1DA4928000F3D412 /* DOMJITReg.h */; settings = {ATTRIBUTES = (Private, ); }; };
E3963CEE1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3963CEC1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp */; };
E39D45F51D39005600B3B377 /* InterpreterInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E39D9D841D39000600667282 /* InterpreterInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
E39DA4A61B7E8B7C0084F33A /* JSModuleRecord.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */; };
@@ -4397,6 +4399,8 @@
E35E03611B7AB4850073AD2A /* InspectorInstrumentationObject.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = InspectorInstrumentationObject.js; sourceTree = "<group>"; };
E3794E731B77EB97005543AE /* ModuleAnalyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ModuleAnalyzer.cpp; sourceTree = "<group>"; };
E3794E741B77EB97005543AE /* ModuleAnalyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleAnalyzer.h; sourceTree = "<group>"; };
+ E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITPatchpointParams.h; sourceTree = "<group>"; };
+ E37AD83B1DA4928000F3D412 /* DOMJITReg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMJITReg.h; sourceTree = "<group>"; };
E3963CEC1B73F75000EB4CE5 /* NodesAnalyzeModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NodesAnalyzeModule.cpp; sourceTree = "<group>"; };
E39D9D841D39000600667282 /* InterpreterInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InterpreterInlines.h; sourceTree = "<group>"; };
E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleRecord.cpp; sourceTree = "<group>"; };
@@ -7183,6 +7187,8 @@
children = (
E3FF752F1D9CEA1200C7E16D /* DOMJITGetterSetter.h */,
E3C08E3B1DA41B7B0039478F /* DOMJITPatchpoint.h */,
+ E37AD83A1DA4928000F3D412 /* DOMJITPatchpointParams.h */,
+ E37AD83B1DA4928000F3D412 /* DOMJITReg.h */,
);
path = domjit;
sourceTree = "<group>";
@@ -7600,6 +7606,7 @@
E39D45F51D39005600B3B377 /* InterpreterInlines.h in Headers */,
0FFB921C16D02F110055A5DB /* DFGOSRExitCompilationInfo.h in Headers */,
0FC0977114693AF500CF2442 /* DFGOSRExitCompiler.h in Headers */,
+ E37AD83D1DA4928600F3D412 /* DOMJITReg.h in Headers */,
0F7025AA1714B0FC00382C0E /* DFGOSRExitCompilerCommon.h in Headers */,
0F392C8A1B46188400844728 /* DFGOSRExitFuzz.h in Headers */,
0FEFC9AB1681A3B600567F53 /* DFGOSRExitJumpPlaceholder.h in Headers */,
@@ -8428,6 +8435,7 @@
9959E92E1BD17FA4001AA413 /* xxd.pl in Headers */,
79B1788E1D399B8000B1A567 /* JITMathICForwards.h in Headers */,
451539B912DC994500EF7AC4 /* Yarr.h in Headers */,
+ E37AD83C1DA4928600F3D412 /* DOMJITPatchpointParams.h in Headers */,
86704B8512DBA33700A9FE7B /* YarrInterpreter.h in Headers */,
86704B8712DBA33700A9FE7B /* YarrJIT.h in Headers */,
0FB4767F1D99AEAD008EA6CB /* GCDeferralContextInlines.h in Headers */,
Modified: trunk/Source/_javascript_Core/b3/B3Effects.h (206845 => 206846)
--- trunk/Source/_javascript_Core/b3/B3Effects.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/b3/B3Effects.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -78,6 +78,15 @@
return result;
}
+ static Effects forCheck()
+ {
+ Effects result;
+ result.exitsSideways = true;
+ // The program could read anything after exiting, and it's on us to declare this.
+ result.reads = HeapRange::top();
+ return result;
+ }
+
bool mustExecute() const
{
return terminal || exitsSideways || writesLocalState || writes;
Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/b3/B3Value.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -614,9 +614,7 @@
case CheckSub:
case CheckMul:
case Check:
- result.exitsSideways = true;
- // The program could read anything after exiting, and it's on us to declare this.
- result.reads = HeapRange::top();
+ result = Effects::forCheck();
break;
case Upsilon:
case Set:
Modified: trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -246,6 +246,7 @@
domJIT = access.domJIT();
if (!domJIT)
return GetByIdStatus(slowPathState, true);
+ result.m_state = Custom;
break;
}
default: {
@@ -263,6 +264,16 @@
if (!result.appendVariant(variant))
return GetByIdStatus(slowPathState, true);
+
+ if (domJIT) {
+ // Give up when cutom accesses are not merged into one.
+ if (result.numVariants() != 1)
+ return GetByIdStatus(slowPathState, true);
+ } else {
+ // Give up when custom access and simple access are mixed.
+ if (result.m_state == Custom)
+ return GetByIdStatus(slowPathState, true);
+ }
break;
} }
}
@@ -362,6 +373,7 @@
switch (m_state) {
case NoInformation:
case TakesSlowPath:
+ case Custom:
return false;
case Simple:
for (unsigned i = m_variants.size(); i--;) {
@@ -403,6 +415,9 @@
case Simple:
out.print("Simple");
break;
+ case Custom:
+ out.print("Custom");
+ break;
case TakesSlowPath:
out.print("TakesSlowPath");
break;
Modified: trunk/Source/_javascript_Core/bytecode/GetByIdStatus.h (206845 => 206846)
--- trunk/Source/_javascript_Core/bytecode/GetByIdStatus.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/bytecode/GetByIdStatus.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -44,6 +44,7 @@
NoInformation, // It's uncached so we have no information.
Simple, // It's cached for a simple access to a known object property with
// a possible structure chain and a possible specific value.
+ Custom, // It's cached for a custom accessor with a possible structure chain.
TakesSlowPath, // It's known to often take slow path.
MakesCalls // It's known to take paths that make calls.
};
@@ -64,7 +65,7 @@
: m_state(state)
, m_wasSeenInJIT(wasSeenInJIT)
{
- ASSERT((state == Simple) == variant.isSet());
+ ASSERT((state == Simple || state == Custom) == variant.isSet());
m_variants.append(variant);
}
@@ -82,6 +83,7 @@
bool isSet() const { return m_state != NoInformation; }
bool operator!() const { return !isSet(); }
bool isSimple() const { return m_state == Simple; }
+ bool isCustom() const { return m_state == Custom; }
size_t numVariants() const { return m_variants.size(); }
const Vector<GetByIdVariant, 1>& variants() const { return m_variants; }
@@ -88,7 +90,7 @@
const GetByIdVariant& at(size_t index) const { return m_variants[index]; }
const GetByIdVariant& operator[](size_t index) const { return at(index); }
- bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; }
+ bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls || m_state == Custom; }
bool makesCalls() const;
bool wasSeenInJIT() const { return m_wasSeenInJIT; }
Modified: trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -353,6 +353,12 @@
SpeculatedType speculationFromClassInfo(const ClassInfo* classInfo)
{
+ if (classInfo == JSString::info())
+ return SpecString;
+
+ if (classInfo == Symbol::info())
+ return SpecSymbol;
+
if (classInfo == JSFinalObject::info())
return SpecFinalObject;
@@ -385,6 +391,9 @@
if (isTypedView(classInfo->typedArrayStorageType))
return speculationFromTypedArrayType(classInfo->typedArrayStorageType);
+
+ if (classInfo->isSubClassOf(JSArray::info()))
+ return SpecDerivedArray;
if (classInfo->isSubClassOf(JSObject::info()))
return SpecObjectOther;
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -134,10 +134,17 @@
return filterByValue(forNode(node), value);
}
+ template<typename T>
+ FiltrationResult filterClassInfo(T node, const ClassInfo* classInfo)
+ {
+ return filterClassInfo(forNode(node), classInfo);
+ }
+
FiltrationResult filter(AbstractValue&, const StructureSet&, SpeculatedType admittedTypes = SpecNone);
FiltrationResult filterArrayModes(AbstractValue&, ArrayModes);
FiltrationResult filter(AbstractValue&, SpeculatedType);
FiltrationResult filterByValue(AbstractValue&, FrozenValue);
+ FiltrationResult filterClassInfo(AbstractValue&, const ClassInfo*);
PhiChildren* phiChildren() { return m_phiChildren.get(); }
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -29,6 +29,7 @@
#include "ArrayConstructor.h"
#include "DFGAbstractInterpreter.h"
+#include "DOMJITGetterSetter.h"
#include "GetByIdStatus.h"
#include "GetterSetter.h"
#include "HashMapImpl.h"
@@ -2268,6 +2269,28 @@
case ReallocatePropertyStorage:
forNode(node).clear(); // The result is not a JS value.
break;
+ case CheckDOM: {
+ JSValue constant = forNode(node->child1()).value();
+ if (constant) {
+ if (constant.isCell() && constant.asCell()->inherits(node->classInfo())) {
+ m_state.setFoundConstants(true);
+ ASSERT(constant);
+ break;
+ }
+ }
+
+ AbstractValue& value = forNode(node->child1());
+
+ if (value.m_structure.isSubClassOf(node->classInfo()))
+ m_state.setFoundConstants(true);
+
+ filterClassInfo(value, node->classInfo());
+ break;
+ }
+ case CallDOM:
+ clobberWorld(node->origin.semantic, clobberLimit);
+ forNode(node).makeBytecodeTop();
+ break;
case CheckArray: {
if (node->arrayMode().alreadyChecked(m_graph, node, forNode(node->child1()))) {
m_state.setFoundConstants(true);
@@ -3056,6 +3079,16 @@
}
template<typename AbstractStateType>
+FiltrationResult AbstractInterpreter<AbstractStateType>::filterClassInfo(
+ AbstractValue& value, const ClassInfo* classInfo)
+{
+ if (value.filterClassInfo(m_graph, classInfo) == FiltrationOK)
+ return FiltrationOK;
+ m_state.setIsValid(false);
+ return Contradiction;
+}
+
+template<typename AbstractStateType>
void AbstractInterpreter<AbstractStateType>::executeDoubleUnaryOpEffects(Node* node, double(*equivalentFunction)(double))
{
JSValue child = forNode(node->child1()).value();
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractValue.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractValue.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractValue.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -306,6 +306,23 @@
return normalizeClarity();
}
+FiltrationResult AbstractValue::filterClassInfo(Graph& graph, const ClassInfo* classInfo)
+{
+ // FIXME: AI should track ClassInfo to leverage hierarchical class information.
+ // https://bugs.webkit.org/show_bug.cgi?id=162989
+ if (isClear())
+ return FiltrationOK;
+
+ m_type &= speculationFromClassInfo(classInfo);
+ m_structure.filterClassInfo(classInfo);
+
+ m_structure.filter(m_type);
+
+ filterArrayModesByType();
+ filterValueByType();
+ return normalizeClarity(graph);
+}
+
FiltrationResult AbstractValue::filter(SpeculatedType type)
{
if ((m_type & type) == m_type)
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractValue.h (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractValue.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractValue.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -307,6 +307,7 @@
FiltrationResult filter(SpeculatedType);
FiltrationResult filterByValue(const FrozenValue& value);
FiltrationResult filter(const AbstractValue&);
+ FiltrationResult filterClassInfo(Graph&, const ClassInfo*);
FiltrationResult filter(Graph&, const InferredType::Descriptor&);
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -219,6 +219,7 @@
bool handleConstantInternalFunction(Node* callTargetNode, int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind, SpeculatedType, const ChecksFunctor& insertChecks);
Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, const InferredType::Descriptor&, Node* value);
Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset, const InferredType::Descriptor&, NodeType = GetByOffset);
+ bool handleDOMJITGetter(int resultOperand, const GetByIdVariant&, Node* thisNode, SpeculatedType prediction);
// Create a presence ObjectPropertyCondition based on some known offset and structure set. Does not
// check the validity of the condition, but it may return a null one if it encounters a contradiction.
@@ -2673,6 +2674,28 @@
RELEASE_ASSERT_NOT_REACHED();
}
+bool ByteCodeParser::handleDOMJITGetter(int resultOperand, const GetByIdVariant& variant, Node* thisNode, SpeculatedType prediction)
+{
+ if (!variant.domJIT())
+ return false;
+
+ DOMJIT::GetterSetter* domJIT = variant.domJIT();
+
+ // We do not need to actually look up CustomGetterSetter here. Checking Structures or registering watchpoints are enough,
+ // since replacement of CustomGetterSetter always incurs Structure transition.
+ if (!check(variant.conditionSet()))
+ return false;
+ addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), thisNode);
+
+ // We do not need to emit CheckCell thingy here. When the custom accessor is replaced to different one, Structure transition occurs.
+ addToGraph(CheckDOM, OpInfo(domJIT), OpInfo(domJIT->thisClassInfo()), thisNode);
+ Node* globalObject = addToGraph(GetGlobalObject, thisNode);
+ addVarArgChild(globalObject); // GlobalObject of thisNode is always used to create a DOMWrapper.
+ addVarArgChild(thisNode);
+ set(VirtualRegister(resultOperand), addToGraph(Node::VarArg, CallDOM, OpInfo(domJIT), OpInfo(prediction)));
+ return true;
+}
+
template<typename ChecksFunctor>
bool ByteCodeParser::handleTypedArrayConstructor(
int resultOperand, InternalFunction* function, int registerOffset,
@@ -3267,6 +3290,20 @@
else
getById = TryGetById;
+ // Special path for custom accessors since custom's offset does not have any meanings.
+ // So, this is completely different from Simple one. But we have a chance to optimize it when we use DOMJIT.
+ if (getByIdStatus.isCustom()) {
+ ASSERT(getByIdStatus.numVariants() == 1);
+ ASSERT(!getByIdStatus.makesCalls());
+ GetByIdVariant variant = getByIdStatus[0];
+ ASSERT(variant.domJIT());
+ if (handleDOMJITGetter(destinationOperand, variant, base, prediction)) {
+ if (m_graph.compilation())
+ m_graph.compilation()->noticeInlinedGetById();
+ return;
+ }
+ }
+
ASSERT(type == AccessType::Get || !getByIdStatus.makesCalls());
if (!getByIdStatus.isSimple() || !getByIdStatus.numVariants() || !Options::useAccessInlining()) {
set(VirtualRegister(destinationOperand),
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -885,6 +885,15 @@
def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
return;
+ case CheckDOM:
+ def(PureValue(node, node->classInfo()));
+ return;
+
+ case CallDOM:
+ read(World);
+ write(Heap);
+ return;
+
case Arrayify:
case ArrayifyToStructure:
read(JSCell_structureID);
Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -158,6 +158,28 @@
}
break;
}
+
+ case CheckDOM: {
+ JSValue constant = m_state.forNode(node->child1()).value();
+ if (constant) {
+ if (constant.isCell() && constant.asCell()->inherits(node->classInfo())) {
+ m_interpreter.execute(indexInBlock);
+ node->remove();
+ eliminated = true;
+ break;
+ }
+ }
+
+ AbstractValue& value = m_state.forNode(node->child1());
+
+ if (value.m_structure.isSubClassOf(node->classInfo())) {
+ m_interpreter.execute(indexInBlock);
+ node->remove();
+ eliminated = true;
+ break;
+ }
+ break;
+ }
case GetIndexedPropertyStorage: {
JSArrayBufferView* view = m_graph.tryGetFoldableView(
Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -118,6 +118,8 @@
case CheckStructure:
case GetExecutable:
case GetButterfly:
+ case CallDOM:
+ case CheckDOM:
case CheckArray:
case GetScope:
case SkipScope:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -1699,6 +1699,15 @@
break;
}
+ case CheckDOM:
+ fixEdge<CellUse>(node->child1());
+ break;
+
+ case CallDOM:
+ fixEdge<KnownCellUse>(m_graph.varArgChild(node, 0)); // GlobalObject.
+ fixEdge<CellUse>(m_graph.varArgChild(node, 1)); // DOM.
+ break;
+
#if !ASSERT_DISABLED
// Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes.
case SetArgument:
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -1446,6 +1446,7 @@
case StringReplaceRegExp:
case ToNumber:
case LoadFromJSMapBucket:
+ case CallDOM:
return true;
default:
return false;
@@ -2312,7 +2313,28 @@
ASSERT(hasBasicBlockLocation());
return m_opInfo.as<BasicBlockLocation*>();
}
-
+
+ bool hasDOMJIT() const
+ {
+ return op() == CheckDOM || op() == CallDOM;
+ }
+
+ DOMJIT::GetterSetter* domJIT()
+ {
+ ASSERT(hasDOMJIT());
+ return m_opInfo.as<DOMJIT::GetterSetter*>();
+ }
+
+ bool hasClassInfo() const
+ {
+ return op() == CheckDOM;
+ }
+
+ const ClassInfo* classInfo()
+ {
+ return m_opInfo2.as<const ClassInfo*>();
+ }
+
Node* replacement() const
{
return m_misc.replacement;
@@ -2392,6 +2414,11 @@
u.int64 = 0;
u.pointer = pointer;
}
+ OpInfoWrapper(const void* constPointer)
+ {
+ u.int64 = 0;
+ u.constPointer = constPointer;
+ }
OpInfoWrapper& operator=(uint32_t int32)
{
u.int64 = 0;
@@ -2415,12 +2442,23 @@
u.pointer = pointer;
return *this;
}
+ OpInfoWrapper& operator=(const void* constPointer)
+ {
+ u.int64 = 0;
+ u.constPointer = constPointer;
+ return *this;
+ }
template <typename T>
- ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value, T>::type
+ ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && !std::is_const<typename std::remove_pointer<T>::type>::value, T>::type
{
return static_cast<T>(u.pointer);
}
template <typename T>
+ ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_pointer<T>::value && std::is_const<typename std::remove_pointer<T>::type>::value, T>::type
+ {
+ return static_cast<T>(u.constPointer);
+ }
+ template <typename T>
ALWAYS_INLINE auto as() const -> typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 4, T>::type
{
return u.int32;
@@ -2434,6 +2472,7 @@
uint32_t int32;
uint64_t int64;
void* pointer;
+ const void* constPointer;
} u;
};
OpInfoWrapper m_opInfo;
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -398,6 +398,9 @@
macro(IsNonEmptyMapBucket, NodeResultBoolean) \
\
macro(ToLowerCase, NodeResultJS) \
+ /* Nodes for DOM JIT */\
+ macro(CheckDOM, NodeMustGenerate) \
+ macro(CallDOM, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
// This enum generates a monotonically increasing id for all Node types,
// and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask).
Modified: trunk/Source/_javascript_Core/dfg/DFGOpInfo.h (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGOpInfo.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGOpInfo.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -43,6 +43,7 @@
explicit OpInfo(uintptr_t value) : m_value(static_cast<uint64_t>(value)) { }
#endif
explicit OpInfo(void* value) : m_value(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value))) { }
+ explicit OpInfo(const void* value) : m_value(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value))) { }
uint64_t m_value;
};
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -699,7 +699,8 @@
case GetClosureVar:
case GetFromArguments:
case LoadFromJSMapBucket:
- case ToNumber: {
+ case ToNumber:
+ case CallDOM: {
setPrediction(m_currentNode->getHeapPrediction());
break;
}
@@ -824,6 +825,9 @@
break;
}
+ case CheckDOM:
+ break;
+
case CallObjectConstructor: {
setPrediction(SpecObject);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -218,6 +218,8 @@
case CheckStructure:
case GetExecutable:
case GetButterfly:
+ case CallDOM:
+ case CheckDOM:
case CheckArray:
case Arrayify:
case ArrayifyToStructure:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -38,6 +38,8 @@
#include "DFGOSRExitFuzz.h"
#include "DFGSaneStringGetByValSlowPathGenerator.h"
#include "DFGSlowPathGenerator.h"
+#include "DOMJITPatchpoint.h"
+#include "DOMJITPatchpointParams.h"
#include "DirectArguments.h"
#include "JITAddGenerator.h"
#include "JITBitAndGenerator.h"
@@ -7111,6 +7113,74 @@
storageResult(resultGPR, node);
}
+static void allocateTemporaryRegistersForPatchpoint(SpeculativeJIT* jit, Vector<GPRTemporary>& gpHolders, Vector<FPRTemporary>& fpHolders, Vector<GPRReg>& gpScratch, Vector<FPRReg>& fpScratch, DOMJIT::Patchpoint& patchpoint)
+{
+ for (unsigned i = 0; i < patchpoint.numGPScratchRegisters; ++i) {
+ GPRTemporary temporary(jit);
+ gpScratch.append(temporary.gpr());
+ gpHolders.append(WTFMove(temporary));
+ }
+
+ for (unsigned i = 0; i < patchpoint.numFPScratchRegisters; ++i) {
+ FPRTemporary temporary(jit);
+ fpScratch.append(temporary.fpr());
+ fpHolders.append(WTFMove(temporary));
+ }
+}
+
+void SpeculativeJIT::compileCallDOM(Node* node)
+{
+ Ref<DOMJIT::Patchpoint> patchpoint = node->domJIT()->callDOM();
+
+ Vector<GPRReg> gpScratch;
+ Vector<FPRReg> fpScratch;
+ Vector<DOMJIT::Reg> regs;
+
+ // FIXME: patchpoint should have a way to tell this can reuse "base" register.
+ // Teaching DFG about DOMJIT::Patchpoint clobber information is nice.
+ SpeculateCellOperand globalObject(this, m_jit.graph().varArgChild(node, 0));
+ SpeculateCellOperand base(this, m_jit.graph().varArgChild(node, 1));
+ JSValueRegsTemporary result(this);
+
+ regs.append(result.regs());
+ regs.append(globalObject.gpr());
+ regs.append(base.gpr());
+#if USE(JSVALUE64)
+ regs.append(static_cast<GPRReg>(GPRInfo::tagMaskRegister));
+ regs.append(static_cast<GPRReg>(GPRInfo::tagTypeNumberRegister));
+#endif
+
+ Vector<GPRTemporary> gpTempraries;
+ Vector<FPRTemporary> fpTempraries;
+ allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, patchpoint.get());
+ DOMJIT::PatchpointParams params(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
+ patchpoint->generator()->run(m_jit, params);
+ jsValueResult(result.regs(), node);
+}
+
+void SpeculativeJIT::compileCheckDOM(Node* node)
+{
+ // FIXME: We can add the fallback implementation that inlines jsDynamicCast things here.
+ Ref<DOMJIT::Patchpoint> patchpoint = node->domJIT()->checkDOM();
+
+ Vector<GPRReg> gpScratch;
+ Vector<FPRReg> fpScratch;
+ Vector<DOMJIT::Reg> regs;
+
+ SpeculateCellOperand base(this, node->child1());
+ GPRReg baseGPR = base.gpr();
+ regs.append(baseGPR);
+
+ Vector<GPRTemporary> gpTempraries;
+ Vector<FPRTemporary> fpTempraries;
+ allocateTemporaryRegistersForPatchpoint(this, gpTempraries, fpTempraries, gpScratch, fpScratch, patchpoint.get());
+
+ DOMJIT::PatchpointParams params(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
+ CCallHelpers::JumpList failureCases = patchpoint->generator()->run(m_jit, params);
+ speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node->child1(), failureCases);
+ noResult(node);
+}
+
GPRReg SpeculativeJIT::temporaryRegisterForPutByVal(GPRTemporary& temporary, ArrayMode arrayMode)
{
if (!putByValWillNeedExtraRegister(arrayMode))
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -2543,6 +2543,8 @@
void compileAllocatePropertyStorage(Node*);
void compileReallocatePropertyStorage(Node*);
void compileGetButterfly(Node*);
+ void compileCallDOM(Node*);
+ void compileCheckDOM(Node*);
#if USE(JSVALUE32_64)
template<typename BaseOperandType, typename PropertyOperandType, typename ValueOperandType, typename TagType>
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -5435,6 +5435,14 @@
break;
}
+ case CallDOM:
+ compileCallDOM(node);
+ break;
+
+ case CheckDOM:
+ compileCheckDOM(node);
+ break;
+
case Unreachable:
unreachable(node);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -5566,6 +5566,14 @@
compileMaterializeNewObject(node);
break;
+ case CallDOM:
+ compileCallDOM(node);
+ break;
+
+ case CheckDOM:
+ compileCheckDOM(node);
+ break;
+
#if ENABLE(FTL_JIT)
case CheckTierUpInLoop: {
MacroAssembler::Jump callTierUp = m_jit.branchAdd32(
Modified: trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -258,6 +258,15 @@
});
}
+void StructureAbstractValue::filterClassInfoSlow(const ClassInfo* classInfo)
+{
+ ASSERT(!isTop());
+ m_set.genericFilter(
+ [&] (Structure* structure) {
+ return structure->classInfo()->isSubClassOf(classInfo);
+ });
+}
+
bool StructureAbstractValue::contains(Structure* structure) const
{
if (isInfinite())
@@ -319,6 +328,19 @@
return overlaps(other.m_set);
}
+bool StructureAbstractValue::isSubClassOf(const ClassInfo* classInfo) const
+{
+ if (isInfinite())
+ return false;
+
+ // Note taht this function returns true if the structure set is empty.
+ for (const Structure* structure : m_set) {
+ if (!structure->classInfo()->isSubClassOf(classInfo))
+ return false;
+ }
+ return true;
+}
+
bool StructureAbstractValue::equalsSlow(const StructureAbstractValue& other) const
{
ASSERT(m_set.m_pointer != other.m_set.m_pointer);
Modified: trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.h (206845 => 206846)
--- trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/dfg/DFGStructureAbstractValue.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -163,6 +163,12 @@
if (isNeitherClearNorTop())
filterSlow(type);
}
+
+ ALWAYS_INLINE void filterClassInfo(const ClassInfo* classInfo)
+ {
+ if (isNeitherClearNorTop())
+ filterClassInfoSlow(classInfo);
+ }
ALWAYS_INLINE bool operator==(const StructureAbstractValue& other) const
{
@@ -231,6 +237,8 @@
bool overlaps(const StructureSet& other) const;
bool overlaps(const StructureAbstractValue& other) const;
+
+ bool isSubClassOf(const ClassInfo*) const;
void validateReferences(const TrackedReferences&) const;
@@ -241,6 +249,7 @@
static const unsigned clobberedSupremacyThreshold = 2;
void filterSlow(SpeculatedType type);
+ void filterClassInfoSlow(const ClassInfo*);
bool mergeSlow(const StructureAbstractValue& other);
bool equalsSlow(const StructureAbstractValue& other) const;
Copied: trunk/Source/_javascript_Core/domjit/DOMJITPatchpointParams.h (from rev 206844, trunk/Source/_javascript_Core/dfg/DFGOpInfo.h) (0 => 206846)
--- trunk/Source/_javascript_Core/domjit/DOMJITPatchpointParams.h (rev 0)
+++ trunk/Source/_javascript_Core/domjit/DOMJITPatchpointParams.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(JIT)
+
+#include "CCallHelpers.h"
+#include "DOMJITReg.h"
+#include "RegisterSet.h"
+
+namespace JSC { namespace DOMJIT {
+
+class PatchpointParams {
+WTF_MAKE_NONCOPYABLE(PatchpointParams);
+public:
+ virtual ~PatchpointParams() { }
+
+ unsigned size() const { return m_regs.size(); }
+ const Reg& at(unsigned index) const { return m_regs[index]; }
+ const Reg& operator[](unsigned index) const { return at(index); }
+
+ GPRReg gpScratch(unsigned index) const { return m_gpScratch[index]; }
+ FPRReg fpScratch(unsigned index) const { return m_fpScratch[index]; }
+
+ PatchpointParams(Vector<Reg>&& regs, Vector<GPRReg>&& gpScratch, Vector<FPRReg>&& fpScratch)
+ : m_regs(WTFMove(regs))
+ , m_gpScratch(WTFMove(gpScratch))
+ , m_fpScratch(WTFMove(fpScratch))
+ {
+ }
+
+private:
+
+ Vector<Reg> m_regs;
+ Vector<GPRReg> m_gpScratch;
+ Vector<FPRReg> m_fpScratch;
+};
+
+} }
+
+#endif
Added: trunk/Source/_javascript_Core/domjit/DOMJITReg.h (0 => 206846)
--- trunk/Source/_javascript_Core/domjit/DOMJITReg.h (rev 0)
+++ trunk/Source/_javascript_Core/domjit/DOMJITReg.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Reg.h"
+#include <wtf/Variant.h>
+
+#if ENABLE(JIT)
+
+namespace JSC { namespace DOMJIT {
+
+// It is quite unfortunate that 32 bit environment exists on DFG! This means that JSValueRegs contains 2 registers
+// in such an environment. If we use GPRReg and FPRReg in DOMJITPatchpointParams, DOMJITPatchpointParams may contain
+// different number of registers in 32bit and 64bit environments when we pass JSValueRegs, it is confusing.
+// Therefore, we introduce an abstraction that DOMJIT::Reg, which is a polymorphic register class. It can refer FPRReg,
+// GPRReg, and "JSValueRegs". Note that isGPR() will return false if the target Reg is "JSValueRegs" even if the
+// environment is 64bit.
+//
+// FIXME: Eventually we should move this class into JSC and make is available for other JIT code.
+// https://bugs.webkit.org/show_bug.cgi?id=162990
+class Reg {
+public:
+ enum class Type : uint8_t {
+ GPR = 0,
+ FPR = 1,
+ JSValue = 2,
+ };
+
+ Reg(GPRReg reg)
+ : m_variant(reg)
+ {
+ }
+
+ Reg(FPRReg reg)
+ : m_variant(reg)
+ {
+ }
+
+ Reg(JSValueRegs regs)
+ : m_variant(regs)
+ {
+ }
+
+ bool isGPR() const { return m_variant.index() == static_cast<unsigned>(Type::GPR); }
+ bool isFPR() const { return m_variant.index() == static_cast<unsigned>(Type::FPR); }
+ bool isJSValueRegs() const { return m_variant.index() == static_cast<unsigned>(Type::JSValue); }
+
+ GPRReg gpr() const
+ {
+ ASSERT(isGPR());
+ return std::experimental::get<GPRReg>(m_variant);
+ }
+ FPRReg fpr() const
+ {
+ ASSERT(isFPR());
+ return std::experimental::get<FPRReg>(m_variant);
+ }
+ JSValueRegs jsValueRegs() const
+ {
+ ASSERT(isJSValueRegs());
+ return std::experimental::get<JSValueRegs>(m_variant);
+ }
+
+private:
+ std::experimental::variant<GPRReg, FPRReg, JSValueRegs> m_variant;
+};
+
+} }
+
+#endif
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -266,6 +266,8 @@
case DefineDataProperty:
case DefineAccessorProperty:
case ToLowerCase:
+ case CheckDOM:
+ case CallDOM:
// These are OK.
break;
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -44,6 +44,8 @@
#include "DFGInPlaceAbstractState.h"
#include "DFGOSRAvailabilityAnalysisPhase.h"
#include "DFGOSRExitFuzz.h"
+#include "DOMJITPatchpoint.h"
+#include "DOMJITPatchpointParams.h"
#include "DirectArguments.h"
#include "FTLAbstractHeapRepository.h"
#include "FTLAvailableRecovery.h"
@@ -1046,6 +1048,12 @@
case ToLowerCase:
compileToLowerCase();
break;
+ case CheckDOM:
+ compileCheckDOM();
+ break;
+ case CallDOM:
+ compileCallDOM();
+ break;
case PhantomLocal:
case LoopHint:
@@ -8712,6 +8720,94 @@
crash();
}
+
+ void compileCheckDOM()
+ {
+ LValue cell = lowCell(m_node->child1());
+
+ RefPtr<DOMJIT::Patchpoint> domJIT = m_node->domJIT()->checkDOM();
+
+ PatchpointValue* patchpoint = m_out.patchpoint(Void);
+ patchpoint->appendSomeRegister(cell);
+ patchpoint->numGPScratchRegisters = domJIT->numGPScratchRegisters;
+ patchpoint->numFPScratchRegisters = domJIT->numFPScratchRegisters;
+
+ State* state = &m_ftlState;
+ NodeOrigin origin = m_origin;
+ unsigned osrExitArgumentOffset = patchpoint->numChildren();
+ OSRExitDescriptor* exitDescriptor = appendOSRExitDescriptor(jsValueValue(cell), m_node->child1().node());
+ patchpoint->appendColdAnys(buildExitArguments(exitDescriptor, origin.forExit, jsValueValue(cell)));
+
+ patchpoint->setGenerator(
+ [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+ Vector<GPRReg> gpScratch;
+ Vector<FPRReg> fpScratch;
+ Vector<DOMJIT::Reg> regs;
+
+ regs.append(params[0].gpr());
+
+ for (unsigned i = 0; i < domJIT->numGPScratchRegisters; ++i)
+ gpScratch.append(params.gpScratch(i));
+
+ for (unsigned i = 0; i < domJIT->numFPScratchRegisters; ++i)
+ fpScratch.append(params.fpScratch(i));
+
+ RefPtr<OSRExitHandle> handle = exitDescriptor->emitOSRExitLater(*state, BadType, origin, params, osrExitArgumentOffset);
+
+ DOMJIT::PatchpointParams domJITParams(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
+ CCallHelpers::JumpList failureCases = domJIT->generator()->run(jit, domJITParams);
+
+ jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+ linkBuffer.link(failureCases, linkBuffer.locationOf(handle->label));
+ });
+ });
+ patchpoint->effects = Effects::forCheck();
+ }
+
+ void compileCallDOM()
+ {
+ LValue globalObject = lowCell(m_graph.varArgChild(m_node, 0));
+ LValue cell = lowCell(m_graph.varArgChild(m_node, 1));
+
+ RefPtr<DOMJIT::Patchpoint> domJIT = m_node->domJIT()->callDOM();
+ PatchpointValue* patchpoint = m_out.patchpoint(Int64);
+ patchpoint->appendSomeRegister(globalObject);
+ patchpoint->appendSomeRegister(cell);
+ patchpoint->append(m_tagMask, ValueRep::lateReg(GPRInfo::tagMaskRegister));
+ patchpoint->append(m_tagTypeNumber, ValueRep::lateReg(GPRInfo::tagTypeNumberRegister));
+ RefPtr<PatchpointExceptionHandle> exceptionHandle = preparePatchpointForExceptions(patchpoint);
+ patchpoint->clobber(RegisterSet::macroScratchRegisters());
+ patchpoint->numGPScratchRegisters = domJIT->numGPScratchRegisters;
+ patchpoint->numFPScratchRegisters = domJIT->numFPScratchRegisters;
+
+ patchpoint->setGenerator(
+ [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+ Vector<GPRReg> gpScratch;
+ Vector<FPRReg> fpScratch;
+ Vector<DOMJIT::Reg> regs;
+
+ // FIXME: patchpoint should have a way to tell this can reuse "base" register.
+ // Teaching DFG about DOMJIT::Patchpoint clobber information is nice.
+ regs.append(JSValueRegs(params[0].gpr()));
+ regs.append(params[1].gpr());
+ regs.append(params[2].gpr());
+ regs.append(params[3].gpr());
+ regs.append(params[4].gpr());
+
+ for (unsigned i = 0; i < domJIT->numGPScratchRegisters; ++i)
+ gpScratch.append(params.gpScratch(i));
+
+ for (unsigned i = 0; i < domJIT->numFPScratchRegisters; ++i)
+ fpScratch.append(params.fpScratch(i));
+
+ Box<CCallHelpers::JumpList> exceptions = exceptionHandle->scheduleExitCreation(params)->jumps(jit);
+
+ DOMJIT::PatchpointParams domJITParams(WTFMove(regs), WTFMove(gpScratch), WTFMove(fpScratch));
+ domJIT->generator()->run(jit, domJITParams);
+ });
+ patchpoint->effects = Effects::forCall();
+ setJSValue(patchpoint);
+ }
void compareEqObjectOrOtherToObject(Edge leftChild, Edge rightChild)
{
Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (206845 => 206846)
--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -1209,9 +1209,9 @@
enum ExceptionCheckKind { NormalExceptionCheck, InvertedExceptionCheck };
enum ExceptionJumpWidth { NormalJumpWidth, FarJumpWidth };
- Jump emitExceptionCheck(
+ JS_EXPORT_PRIVATE Jump emitExceptionCheck(
ExceptionCheckKind = NormalExceptionCheck, ExceptionJumpWidth = NormalJumpWidth);
- Jump emitNonPatchableExceptionCheck();
+ JS_EXPORT_PRIVATE Jump emitNonPatchableExceptionCheck();
#if ENABLE(SAMPLING_COUNTERS)
static void emitCount(MacroAssembler& jit, AbstractSamplingCounter& counter, int32_t increment = 1)
Modified: trunk/Source/_javascript_Core/jsc.cpp (206845 => 206846)
--- trunk/Source/_javascript_Core/jsc.cpp 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/_javascript_Core/jsc.cpp 2016-10-06 05:20:10 UTC (rev 206846)
@@ -28,6 +28,9 @@
#include "ButterflyInlines.h"
#include "CodeBlock.h"
#include "Completion.h"
+#include "DOMJITGetterSetter.h"
+#include "DOMJITPatchpoint.h"
+#include "DOMJITPatchpointParams.h"
#include "Disassembler.h"
#include "Exception.h"
#include "ExceptionHelpers.h"
@@ -72,6 +75,7 @@
#include <type_traits>
#include <wtf/CurrentTime.h>
#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/StringPrintStream.h>
#include <wtf/text/StringBuilder.h>
@@ -537,12 +541,133 @@
WriteBarrier<JSC::Unknown> m_hiddenValue;
};
+class DOMJITNode : public JSNonFinalObject {
+public:
+ DOMJITNode(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+ DECLARE_INFO;
+ typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
+ }
+
+ static DOMJITNode* create(VM& vm, Structure* structure)
+ {
+ DOMJITNode* getter = new (NotNull, allocateCell<DOMJITNode>(vm.heap, sizeof(DOMJITNode))) DOMJITNode(vm, structure);
+ getter->finishCreation(vm);
+ return getter;
+ }
+
+ int32_t value() const
+ {
+ return m_value;
+ }
+
+ static ptrdiff_t offsetOfValue() { return OBJECT_OFFSETOF(DOMJITNode, m_value); }
+
+private:
+ int32_t m_value { 42 };
+};
+
+class DOMJITGetter : public DOMJITNode {
+public:
+ DOMJITGetter(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ DECLARE_INFO;
+ typedef DOMJITNode Base;
+ static const unsigned StructureFlags = Base::StructureFlags;
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
+ }
+
+ static DOMJITGetter* create(VM& vm, Structure* structure)
+ {
+ DOMJITGetter* getter = new (NotNull, allocateCell<DOMJITGetter>(vm.heap, sizeof(DOMJITGetter))) DOMJITGetter(vm, structure);
+ getter->finishCreation(vm);
+ return getter;
+ }
+
+ class DOMJITNodeDOMJIT : public DOMJIT::GetterSetter {
+ public:
+ DOMJITNodeDOMJIT()
+ : DOMJIT::GetterSetter(DOMJITGetter::customGetter, nullptr, DOMJITNode::info())
+ {
+ }
+
+ Ref<DOMJIT::Patchpoint> checkDOM() override
+ {
+ Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
+ patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+ CCallHelpers::JumpList failureCases;
+ failureCases.append(jit.branch8(
+ CCallHelpers::NotEqual,
+ CCallHelpers::Address(params[0].gpr(), JSCell::typeInfoTypeOffset()),
+ CCallHelpers::TrustedImm32(JSC::JSType(LastJSCObjectType + 1))));
+ return failureCases;
+ });
+ return patchpoint;
+ }
+
+ Ref<DOMJIT::Patchpoint> callDOM() override
+ {
+ Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
+ patchpoint->setGenerator([=](CCallHelpers& jit, const DOMJIT::PatchpointParams& params) {
+ JSValueRegs results = params[0].jsValueRegs();
+ GPRReg dom = params[2].gpr();
+
+ jit.load32(CCallHelpers::Address(dom, DOMJITNode::offsetOfValue()), results.payloadGPR());
+ jit.boxInt32(results.payloadGPR(), results);
+ return CCallHelpers::JumpList();
+ });
+ return patchpoint;
+ }
+ };
+
+ static DOMJIT::GetterSetter* domJITNodeGetterSetter()
+ {
+ static NeverDestroyed<DOMJITNodeDOMJIT> graph;
+ return &graph.get();
+ }
+
+private:
+ void finishCreation(VM& vm)
+ {
+ Base::finishCreation(vm);
+ DOMJIT::GetterSetter* domJIT = domJITNodeGetterSetter();
+ CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, domJIT->getter(), domJIT->setter(), domJIT);
+ putDirectCustomAccessor(vm, Identifier::fromString(&vm, "customGetter"), customGetterSetter, ReadOnly | CustomAccessor);
+ }
+
+ static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
+ {
+ VM& vm = exec->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(JSValue::decode(thisValue));
+ if (!thisObject)
+ return throwVMTypeError(exec, scope);
+ return JSValue::encode(jsNumber(thisObject->value()));
+ }
+};
+
const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, CREATE_METHOD_TABLE(Root) };
const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(ImpureGetter) };
const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
+const ClassInfo DOMJITNode::s_info = { "DOMJITNode", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITNode) };
+const ClassInfo DOMJITGetter::s_info = { "DOMJITGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(DOMJITGetter) };
const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, 0, CREATE_METHOD_TABLE(SimpleObject) };
static bool test262AsyncPassed { false };
@@ -571,6 +696,8 @@
static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
@@ -855,6 +982,8 @@
addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
addFunction(vm, "createCustomGetterObject", functionCreateCustomGetterObject, 0);
+ addFunction(vm, "createDOMJITNodeObject", functionCreateDOMJITNodeObject, 0);
+ addFunction(vm, "createDOMJITGetterObject", functionCreateDOMJITGetterObject, 0);
addFunction(vm, "createBuiltin", functionCreateBuiltin, 2);
addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0);
addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
@@ -1359,6 +1488,22 @@
return JSValue::encode(result);
}
+EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState* exec)
+{
+ JSLockHolder lock(exec);
+ Structure* structure = DOMJITNode::createStructure(exec->vm(), exec->lexicalGlobalObject(), DOMJITGetter::create(exec->vm(), DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull())));
+ DOMJITNode* result = DOMJITNode::create(exec->vm(), structure);
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState* exec)
+{
+ JSLockHolder lock(exec);
+ Structure* structure = DOMJITGetter::createStructure(exec->vm(), exec->lexicalGlobalObject(), jsNull());
+ DOMJITGetter* result = DOMJITGetter::create(exec->vm(), structure);
+ return JSValue::encode(result);
+}
+
EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
{
JSLockHolder lock(exec);
Modified: trunk/Source/WTF/ChangeLog (206845 => 206846)
--- trunk/Source/WTF/ChangeLog 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/WTF/ChangeLog 2016-10-06 05:20:10 UTC (rev 206846)
@@ -1,3 +1,13 @@
+2016-10-05 Yusuke Suzuki <[email protected]>
+
+ [DOMJIT] Add initial CheckDOM and CallDOM implementations
+ https://bugs.webkit.org/show_bug.cgi?id=162941
+
+ Reviewed by Filip Pizlo.
+
+ * wtf/Box.h:
+ (WTF::Box::Box):
+
2016-10-05 Zan Dobersek <[email protected]>
Rename ENABLE_ENCRYPTED_MEDIA_V2 to ENABLE_LEGACY_ENCRYPTED_MEDIA
Modified: trunk/Source/WTF/wtf/Box.h (206845 => 206846)
--- trunk/Source/WTF/wtf/Box.h 2016-10-06 05:15:32 UTC (rev 206845)
+++ trunk/Source/WTF/wtf/Box.h 2016-10-06 05:20:10 UTC (rev 206846)
@@ -40,6 +40,10 @@
{
}
+ Box(std::nullptr_t)
+ {
+ }
+
template<typename... Arguments>
static Box create(Arguments&&... arguments)
{