[DOMJIT] Use NativeCallFrameTracer for operations used for DOMJIT slow calls
[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 "DOMJITHelpers.h"
32 #include "JSDOMWrapper.h"
33 #include "Node.h"
34 #include <domjit/DOMJITPatchpoint.h>
35 #include <domjit/DOMJITPatchpointParams.h>
36 #include <interpreter/FrameTracers.h>
37
38 using namespace JSC;
39
40 namespace WebCore {
41
42 enum class IsContainerGuardRequirement { Required, NotRequired };
43
44 template<typename WrappedNode>
45 EncodedJSValue JIT_OPERATION toWrapperSlow(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject, void* result)
46 {
47     ASSERT(exec);
48     ASSERT(result);
49     ASSERT(globalObject);
50     JSC::NativeCallFrameTracer tracer(&exec->vm(), exec);
51     return JSValue::encode(toJS(exec, static_cast<JSDOMGlobalObject*>(globalObject), *static_cast<WrappedNode*>(result)));
52 }
53
54 template<typename WrappedNode>
55 static Ref<DOMJIT::CallDOMPatchpoint> createCallDOMForOffsetAccess(ptrdiff_t offset, IsContainerGuardRequirement isContainerGuardRequirement)
56 {
57     Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
58     patchpoint->numGPScratchRegisters = 1;
59     patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
60         JSValueRegs result = params[0].jsValueRegs();
61         GPRReg globalObject = params[1].gpr();
62         GPRReg node = params[2].gpr();
63         GPRReg scratch = params.gpScratch(0);
64
65         CCallHelpers::JumpList nullCases;
66         // Load a wrapped object. "node" should be already type checked by CheckDOM.
67         jit.loadPtr(CCallHelpers::Address(node, JSNode::offsetOfWrapped()), scratch);
68
69         if (isContainerGuardRequirement == IsContainerGuardRequirement::Required)
70             nullCases.append(jit.branchTest32(CCallHelpers::Zero, CCallHelpers::Address(scratch, Node::nodeFlagsMemoryOffset()), CCallHelpers::TrustedImm32(Node::flagIsContainer())));
71
72         jit.loadPtr(CCallHelpers::Address(scratch, offset), scratch);
73         nullCases.append(jit.branchTestPtr(CCallHelpers::Zero, scratch));
74
75         DOMJITHelpers::toWrapper<WrappedNode>(jit, params, scratch, globalObject, result, toWrapperSlow<WrappedNode>, params[1].value());
76         CCallHelpers::Jump done = jit.jump();
77
78         nullCases.link(&jit);
79         jit.moveValue(jsNull(), result);
80         done.link(&jit);
81         return CCallHelpers::JumpList();
82     });
83     return patchpoint;
84 }
85
86 static Ref<DOMJIT::Patchpoint> checkNode()
87 {
88     Ref<DOMJIT::Patchpoint> patchpoint = DOMJIT::Patchpoint::create();
89     patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
90         CCallHelpers::JumpList failureCases;
91         failureCases.append(DOMJITHelpers::branchIfNotNode(jit, params[0].gpr()));
92         return failureCases;
93     });
94     return patchpoint;
95 }
96
97 // Node#firstChild.
98 Ref<DOMJIT::Patchpoint> NodeFirstChildDOMJIT::checkDOM()
99 {
100     return checkNode();
101 }
102
103 Ref<DOMJIT::CallDOMPatchpoint> NodeFirstChildDOMJIT::callDOM()
104 {
105     return createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::firstChildMemoryOffset(), IsContainerGuardRequirement::Required);
106 }
107
108 // Node#lastChild.
109 Ref<DOMJIT::Patchpoint> NodeLastChildDOMJIT::checkDOM()
110 {
111     return checkNode();
112 }
113
114 Ref<DOMJIT::CallDOMPatchpoint> NodeLastChildDOMJIT::callDOM()
115 {
116     return createCallDOMForOffsetAccess<Node>(CAST_OFFSET(Node*, ContainerNode*) + ContainerNode::lastChildMemoryOffset(), IsContainerGuardRequirement::Required);
117 }
118
119 // Node#nextSibling.
120 Ref<DOMJIT::Patchpoint> NodeNextSiblingDOMJIT::checkDOM()
121 {
122     return checkNode();
123 }
124
125 Ref<DOMJIT::CallDOMPatchpoint> NodeNextSiblingDOMJIT::callDOM()
126 {
127     return createCallDOMForOffsetAccess<Node>(Node::nextSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
128 }
129
130 // Node#previousSibling.
131 Ref<DOMJIT::Patchpoint> NodePreviousSiblingDOMJIT::checkDOM()
132 {
133     return checkNode();
134 }
135
136 Ref<DOMJIT::CallDOMPatchpoint> NodePreviousSiblingDOMJIT::callDOM()
137 {
138     return createCallDOMForOffsetAccess<Node>(Node::previousSiblingMemoryOffset(), IsContainerGuardRequirement::NotRequired);
139 }
140
141 // Node#parentNode.
142 Ref<DOMJIT::Patchpoint> NodeParentNodeDOMJIT::checkDOM()
143 {
144     return checkNode();
145 }
146
147 Ref<DOMJIT::CallDOMPatchpoint> NodeParentNodeDOMJIT::callDOM()
148 {
149     return createCallDOMForOffsetAccess<ContainerNode>(Node::parentNodeMemoryOffset(), IsContainerGuardRequirement::NotRequired);
150 }
151
152 // Node#nodeType.
153 Ref<DOMJIT::Patchpoint> NodeNodeTypeDOMJIT::checkDOM()
154 {
155     return checkNode();
156 }
157
158 Ref<DOMJIT::CallDOMPatchpoint> NodeNodeTypeDOMJIT::callDOM()
159 {
160     Ref<DOMJIT::CallDOMPatchpoint> patchpoint = DOMJIT::CallDOMPatchpoint::create();
161     patchpoint->requireGlobalObject = false;
162     patchpoint->setGenerator([=](CCallHelpers& jit, DOMJIT::PatchpointParams& params) {
163         JSValueRegs result = params[0].jsValueRegs();
164         GPRReg node = params[1].gpr();
165         jit.load8(CCallHelpers::Address(node, JSC::JSCell::typeInfoTypeOffset()), result.payloadGPR());
166         jit.and32(CCallHelpers::TrustedImm32(JSNodeTypeMask), result.payloadGPR());
167         jit.boxInt32(result.payloadGPR(), result);
168         return CCallHelpers::JumpList();
169     });
170     return patchpoint;
171 }
172
173 }
174
175 #endif