0c2ed19c982defd1b53823461583a0b596b51a84
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGLazyJSValue.cpp
1 /*
2  * Copyright (C) 2013, 2014, 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 "DFGLazyJSValue.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "CCallHelpers.h"
32 #include "DFGGraph.h"
33 #include "JSCInlines.h"
34 #include "LinkBuffer.h"
35
36 namespace JSC { namespace DFG {
37
38 LazyJSValue LazyJSValue::newString(Graph& graph, const String& string)
39 {
40     LazyJSValue result;
41     result.m_kind = NewStringImpl;
42     result.u.stringImpl = graph.m_localStrings.add(string).iterator->impl();
43     return result;
44 }
45
46 JSValue LazyJSValue::getValue(VM& vm) const
47 {
48     switch (m_kind) {
49     case KnownValue:
50         return value()->value();
51     case SingleCharacterString:
52         return jsSingleCharacterString(&vm, u.character);
53     case KnownStringImpl:
54     case NewStringImpl:
55         return jsString(&vm, u.stringImpl);
56     }
57     RELEASE_ASSERT_NOT_REACHED();
58     return JSValue();
59 }
60
61 static TriState equalToSingleCharacter(JSValue value, UChar character)
62 {
63     if (!value.isString())
64         return FalseTriState;
65     
66     JSString* jsString = asString(value);
67     if (jsString->length() != 1)
68         return FalseTriState;
69     
70     const StringImpl* string = jsString->tryGetValueImpl();
71     if (!string)
72         return MixedTriState;
73     
74     return triState(string->at(0) == character);
75 }
76
77 static TriState equalToStringImpl(JSValue value, StringImpl* stringImpl)
78 {
79     if (!value.isString())
80         return FalseTriState;
81     
82     JSString* jsString = asString(value);
83     const StringImpl* string = jsString->tryGetValueImpl();
84     if (!string)
85         return MixedTriState;
86     
87     return triState(WTF::equal(stringImpl, string));
88 }
89
90 const StringImpl* LazyJSValue::tryGetStringImpl() const
91 {
92     switch (m_kind) {
93     case KnownStringImpl:
94     case NewStringImpl:
95         return u.stringImpl;
96
97     case KnownValue:
98         if (JSString* string = jsDynamicCast<JSString*>(value()->value()))
99             return string->tryGetValueImpl();
100         return nullptr;
101
102     default:
103         return nullptr;
104     }
105 }
106
107 String LazyJSValue::tryGetString(Graph& graph) const
108 {
109     switch (m_kind) {
110     case NewStringImpl:
111         return u.stringImpl;
112
113     case SingleCharacterString:
114         return String(&u.character, 1);
115
116     default:
117         if (const StringImpl* string = tryGetStringImpl()) {
118             unsigned ginormousStringLength = 10000;
119             if (string->length() > ginormousStringLength)
120                 return String();
121             
122             auto result = graph.m_copiedStrings.add(string, String());
123             if (result.isNewEntry)
124                 result.iterator->value = string->isolatedCopy();
125             return result.iterator->value;
126         }
127         
128         return String();
129     }
130 }
131
132 TriState LazyJSValue::strictEqual(const LazyJSValue& other) const
133 {
134     switch (m_kind) {
135     case KnownValue:
136         switch (other.m_kind) {
137         case KnownValue:
138             return JSValue::pureStrictEqual(value()->value(), other.value()->value());
139         case SingleCharacterString:
140             return equalToSingleCharacter(value()->value(), other.character());
141         case KnownStringImpl:
142         case NewStringImpl:
143             return equalToStringImpl(value()->value(), other.stringImpl());
144         }
145         break;
146     case SingleCharacterString:
147         switch (other.m_kind) {
148         case SingleCharacterString:
149             return triState(character() == other.character());
150         case KnownStringImpl:
151         case NewStringImpl:
152             if (other.stringImpl()->length() != 1)
153                 return FalseTriState;
154             return triState(other.stringImpl()->at(0) == character());
155         default:
156             return other.strictEqual(*this);
157         }
158         break;
159     case KnownStringImpl:
160     case NewStringImpl:
161         switch (other.m_kind) {
162         case KnownStringImpl:
163         case NewStringImpl:
164             return triState(WTF::equal(stringImpl(), other.stringImpl()));
165         default:
166             return other.strictEqual(*this);
167         }
168         break;
169     }
170     RELEASE_ASSERT_NOT_REACHED();
171     return FalseTriState;
172 }
173
174 uintptr_t LazyJSValue::switchLookupValue(SwitchKind kind) const
175 {
176     // NB. Not every kind of JSValue will be able to give you a switch lookup
177     // value, and this method will assert, or do bad things, if you use it
178     // for a kind of value that can't.
179     switch (m_kind) {
180     case KnownValue:
181         switch (kind) {
182         case SwitchImm:
183             return value()->value().asInt32();
184         case SwitchCell:
185             return bitwise_cast<uintptr_t>(value()->value().asCell());
186         default:
187             RELEASE_ASSERT_NOT_REACHED();
188             return 0;
189         }
190     case SingleCharacterString:
191         switch (kind) {
192         case SwitchChar:
193             return character();
194         default:
195             RELEASE_ASSERT_NOT_REACHED();
196             return 0;
197         }
198     default:
199         RELEASE_ASSERT_NOT_REACHED();
200         return 0;
201     }
202 }
203
204 void LazyJSValue::emit(CCallHelpers& jit, JSValueRegs result) const
205 {
206     if (m_kind == KnownValue) {
207         jit.moveValue(value()->value(), result);
208         return;
209     }
210
211     // It must be some kind of cell.
212 #if USE(JSVALUE32_64)
213     jit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), result.tagGPR());
214 #endif
215     CCallHelpers::DataLabelPtr label = jit.moveWithPatch(
216         CCallHelpers::TrustedImmPtr(static_cast<size_t>(0xd1e7beeflu)),
217         result.payloadGPR());
218
219     LazyJSValue thisValue = *this;
220
221     // Once we do this, we're committed. Otherwise we leak memory. Note that we call ref/deref
222     // manually to ensure that there is no concurrency shadiness. We are doing something here
223     // that might be rather brutal: transfering ownership of this string.
224     if (m_kind == NewStringImpl)
225         thisValue.u.stringImpl->ref();
226
227     CodeBlock* codeBlock = jit.codeBlock();
228     
229     jit.addLinkTask(
230         [codeBlock, label, thisValue] (LinkBuffer& linkBuffer) {
231             JSValue realValue = thisValue.getValue(linkBuffer.vm());
232             RELEASE_ASSERT(realValue.isCell());
233
234             codeBlock->addConstant(realValue);
235             
236             if (thisValue.m_kind == NewStringImpl)
237                 thisValue.u.stringImpl->deref();
238
239             linkBuffer.patch(label, realValue.asCell());
240         });
241 }
242
243 void LazyJSValue::dumpInContext(PrintStream& out, DumpContext* context) const
244 {
245     switch (m_kind) {
246     case KnownValue:
247         value()->dumpInContext(out, context);
248         return;
249     case SingleCharacterString:
250         out.print("Lazy:SingleCharacterString(");
251         out.printf("%04X", static_cast<unsigned>(character()));
252         out.print(" / ", StringImpl::utf8ForCharacters(&u.character, 1), ")");
253         return;
254     case KnownStringImpl:
255         out.print("Lazy:KnownString(", stringImpl(), ")");
256         return;
257     case NewStringImpl:
258         out.print("Lazy:NewString(", stringImpl(), ")");
259         return;
260     }
261     RELEASE_ASSERT_NOT_REACHED();
262 }
263
264 void LazyJSValue::dump(PrintStream& out) const
265 {
266     dumpInContext(out, 0);
267 }
268
269 } } // namespace JSC::DFG
270
271 #endif // ENABLE(DFG_JIT)
272