Unreviewed, attempt to fix Windows build after r207787
[WebKit-https.git] / Source / WebCore / domjit / JSNodeDOMJIT.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "JSNode.h"
28
29 #if ENABLE(JIT)
30
31 #include "DOMJITAbstractHeapRepository.h"
32 #include "DOMJITHelpers.h"
33 #include "JSDOMWrapper.h"
34 #include "Node.h"
35 #include <domjit/DOMJITPatchpoint.h>
36 #include <domjit/DOMJITPatchpointParams.h>
37 #include <interpreter/FrameTracers.h>
38
39 using namespace JSC;
40
41 namespace WebCore {
42
43 enum class IsContainerGuardRequirement { Required, NotRequired };
44
45 template<typename WrappedNode>
46 EncodedJSValue JIT_OPERATION toWrapperSlow(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject, void* result)
47 {
48     ASSERT(exec);
49     ASSERT(result);
50     ASSERT(globalObject);
51     JSC::NativeCallFrameTracer tracer(&exec->vm(), exec);
52     return JSValue::encode(toJS(exec, static_cast<JSDOMGlobalObject*>(globalObject), *static_cast<WrappedNode*>(result)));
53 }
54
55 template<typename WrappedNode>
56 static Ref<JSC::DOMJIT::CallDOMPatchpoint> createCallDOMForOffsetAccess(ptrdiff_t offset, IsContainerGuardRequirement isContainerGuardRequirement)
57 {
58     Ref<JSC::DOMJIT::CallDOMPatchpoint> patchpoint = JSC::DOMJIT::CallDOMPatchpoint::create();
59     patchpoint->numGPScratchRegisters = 1;
60     patchpoint->setGenerator([=](CCallHelpers& jit, JSC::DOMJIT::PatchpointParams& params) {
61         JSValueRegs result = params[0].jsValueRegs();
62         GPRReg node = params[1].gpr();
63         GPRReg globalObject = params[2].gpr();
64         GPRReg scratch = params.gpScratch(0);
65         JSValue globalObjectValue = params[2].value();
66
67         CCallHelpers::JumpList nullCases;
68         // Load a wrapped object. "node" should be already type checked by CheckDOM.
69         jit.loadPtr(CCallHelpers::Address(node, JSNode::offsetOfWrapped()), scratch);
70
71         if (isContainerGuardRequirement == IsContainerGuardRequirement::Required)
72             nullCases.append(jit.branchTest32(CCallHelpers::Zero, CCallHelpers::Address(scratch, Node::nodeFlagsMemoryOffset()), CCallHelpers::TrustedImm32(Node::flagIsContainer())));
73
74         jit.loadPtr(CCallHelpers::Address(scratch, offset), scratch);
75         nullCases.append(jit.branchTestPtr(CCallHelpers::Zero, scratch));
76
77         DOMJIT::toWrapper<WrappedNode>(jit, params, scratch, globalObject, result, toWrapperSlow<WrappedNode>, globalObjectValue);
78         CCallHelpers::Jump done = jit.jump();
79
80         nullCases.link(&jit);
81         jit.moveValue(jsNull(), result);
82         done.link(&jit);
83         return CCallHelpers::JumpList();
84     });
85     return patchpoint;
86 }
87
88 static Ref<JSC::DOMJIT::Patchpoint> checkNode()
89 {
90     Ref<JSC::DOMJIT::Patchpoint> patchpoint = JSC::DOMJIT::Patchpoint::create();
91     patchpoint->setGenerator([=](CCallHelpers& jit, JSC::DOMJIT::PatchpointParams& params) {
92         CCallHelpers::JumpList failureCases;
93         failureCases.append(DOMJIT::branchIfNotNode(jit, params[0].gpr()));
94         return failureCases;
95     });
96     return patchpoint;
97 }
98
99 // Node#firstChild.
100 Ref<JSC::DOMJIT::Patchpoint> NodeFirstChildDOMJIT::checkDOM()
101 {
102     return checkNode();
103 }
104
105 Ref<JSC::DOMJIT::CallDOMPatchpoint> NodeFirstChildDOMJIT::callDOM()
106 {
107     const auto& heap = DOMJIT::AbstractHeapRepository::shared();
108     auto patchpoint = createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::firstChildMemoryOffset(), IsContainerGuardRequirement::Required);
109     patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_firstChild);
110     return patchpoint;
111 }
112
113 // Node#lastChild.
114 Ref<JSC::DOMJIT::Patchpoint> NodeLastChildDOMJIT::checkDOM()
115 {
116     return checkNode();
117 }
118
119 Ref<JSC::DOMJIT::CallDOMPatchpoint> NodeLastChildDOMJIT::callDOM()
120 {
121     const auto& heap = DOMJIT::AbstractHeapRepository::shared();
122     auto patchpoint = createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::lastChildMemoryOffset(), IsContainerGuardRequirement::Required);
123     patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_lastChild);
124     return patchpoint;
125 }
126
127 // Node#nextSibling.
128 Ref<JSC::DOMJIT::Patchpoint> NodeNextSiblingDOMJIT::checkDOM()
129 {
130     return checkNode();
131 }
132
133 Ref<JSC::DOMJIT::CallDOMPatchpoint> NodeNextSiblingDOMJIT::callDOM()
134 {
135     const auto& heap = DOMJIT::AbstractHeapRepository::shared();
136     auto patchpoint = createCallDOMForOffsetAccess<Node>(Node::nextSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
137     patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_nextSibling);
138     return patchpoint;
139 }
140
141 // Node#previousSibling.
142 Ref<JSC::DOMJIT::Patchpoint> NodePreviousSiblingDOMJIT::checkDOM()
143 {
144     return checkNode();
145 }
146
147 Ref<JSC::DOMJIT::CallDOMPatchpoint> NodePreviousSiblingDOMJIT::callDOM()
148 {
149     const auto& heap = DOMJIT::AbstractHeapRepository::shared();
150     auto patchpoint = createCallDOMForOffsetAccess<Node>(Node::previousSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
151     patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_previousSibling);
152     return patchpoint;
153 }
154
155 // Node#parentNode.
156 Ref<JSC::DOMJIT::Patchpoint> NodeParentNodeDOMJIT::checkDOM()
157 {
158     return checkNode();
159 }
160
161 Ref<JSC::DOMJIT::CallDOMPatchpoint> NodeParentNodeDOMJIT::callDOM()
162 {
163     const auto& heap = DOMJIT::AbstractHeapRepository::shared();
164     auto patchpoint = createCallDOMForOffsetAccess<ContainerNode>(Node::parentNodeMemoryOffset(), IsContainerGuardRequirement::NotRequired);
165     patchpoint->effect = JSC::DOMJIT::Effect::forDef(heap.Node_parentNode);
166     return patchpoint;
167 }
168
169 // Node#nodeType.
170 Ref<JSC::DOMJIT::Patchpoint> NodeNodeTypeDOMJIT::checkDOM()
171 {
172     return checkNode();
173 }
174
175 Ref<JSC::DOMJIT::CallDOMPatchpoint> NodeNodeTypeDOMJIT::callDOM()
176 {
177     Ref<JSC::DOMJIT::CallDOMPatchpoint> patchpoint = JSC::DOMJIT::CallDOMPatchpoint::create();
178     patchpoint->effect = JSC::DOMJIT::Effect::forPure();
179     patchpoint->requireGlobalObject = false;
180     patchpoint->setGenerator([=](CCallHelpers& jit, JSC::DOMJIT::PatchpointParams& params) {
181         JSValueRegs result = params[0].jsValueRegs();
182         GPRReg node = params[1].gpr();
183         jit.load8(CCallHelpers::Address(node, JSC::JSCell::typeInfoTypeOffset()), result.payloadGPR());
184         jit.and32(CCallHelpers::TrustedImm32(JSNodeTypeMask), result.payloadGPR());
185         jit.boxInt32(result.payloadGPR(), result);
186         return CCallHelpers::JumpList();
187     });
188     return patchpoint;
189 }
190
191 }
192
193 #endif