Line 0
Link Here
|
|
|
1 |
/* |
2 |
* Copyright (C) 2018 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 |
#pragma once |
27 |
|
28 |
#include "BytecodeLivenessAnalysis.h" |
29 |
#include "JSCast.h" |
30 |
#include "JSImmutableButterfly.h" |
31 |
#include "ScopedArgumentsTable.h" |
32 |
#include "SourceCodeKey.h" |
33 |
#include "UnlinkedEvalCodeBlock.h" |
34 |
#include "UnlinkedFunctionCodeBlock.h" |
35 |
#include "UnlinkedMetadataTableInlines.h" |
36 |
#include "UnlinkedModuleProgramCodeBlock.h" |
37 |
#include "UnlinkedProgramCodeBlock.h" |
38 |
#include <wtf/FastMalloc.h> |
39 |
#include <wtf/Forward.h> |
40 |
#include <wtf/Optional.h> |
41 |
#include <wtf/text/AtomicStringImpl.h> |
42 |
|
43 |
namespace JSC { |
44 |
|
45 |
template <typename T, typename = void> |
46 |
struct SourceTypeImpl { |
47 |
using type = T; |
48 |
}; |
49 |
|
50 |
template<typename T> |
51 |
struct SourceTypeImpl<T, std::enable_if_t<!std::is_fundamental<T>::value && !std::is_same<typename T::SourceType, void>::value>> { |
52 |
using type = typename T::SourceType; |
53 |
|
54 |
}; |
55 |
|
56 |
template<typename T> |
57 |
using SourceType = typename SourceTypeImpl<T>::type; |
58 |
|
59 |
class Encoder { |
60 |
WTF_MAKE_NONCOPYABLE(Encoder); |
61 |
|
62 |
public: |
63 |
Encoder(VM& vm) |
64 |
: m_vm(vm) |
65 |
, m_offset(0) |
66 |
{ |
67 |
m_buffer = (uint8_t*)fastZeroedMalloc(s_maxSize); |
68 |
} |
69 |
|
70 |
~Encoder() |
71 |
{ |
72 |
if (m_buffer) |
73 |
fastFree(m_buffer); |
74 |
} |
75 |
|
76 |
VM& vm() { return m_vm; } |
77 |
const uint8_t* buffer() const { return m_buffer; } |
78 |
size_t size() const { return m_offset; } |
79 |
|
80 |
ptrdiff_t mallocOffset(unsigned size) |
81 |
{ |
82 |
m_offset = WTF::roundUpToMultipleOf(sizeof(void*), m_offset); |
83 |
ASSERT(static_cast<size_t>(m_offset + size) < s_maxSize); |
84 |
ptrdiff_t result = m_offset; |
85 |
m_offset += size; |
86 |
return result; |
87 |
} |
88 |
|
89 |
uint8_t* malloc(unsigned size) |
90 |
{ |
91 |
ptrdiff_t offset = mallocOffset(size); |
92 |
return m_buffer + offset; |
93 |
} |
94 |
|
95 |
template<typename T> |
96 |
T* malloc() |
97 |
{ |
98 |
return reinterpret_cast<T*>(malloc(sizeof(T))); |
99 |
} |
100 |
|
101 |
ptrdiff_t offsetOf(const void* address) |
102 |
{ |
103 |
const uint8_t* addr = static_cast<const uint8_t*>(address); |
104 |
ASSERT(addr >= m_buffer && addr < m_buffer + m_offset); |
105 |
return addr - m_buffer; |
106 |
} |
107 |
|
108 |
void cachePtr(const void* ptr, ptrdiff_t offset) |
109 |
{ |
110 |
m_ptrToOffsetMap.add(ptr, offset); |
111 |
} |
112 |
|
113 |
std::optional<ptrdiff_t> offsetForPtr(const void* ptr) |
114 |
{ |
115 |
auto it = m_ptrToOffsetMap.find(ptr); |
116 |
if (it == m_ptrToOffsetMap.end()) |
117 |
return std::nullopt; |
118 |
return { it->value }; |
119 |
} |
120 |
|
121 |
private: |
122 |
unsigned s_maxSize = 10 * MB; |
123 |
|
124 |
VM& m_vm; |
125 |
uint8_t* m_buffer; |
126 |
ptrdiff_t m_offset; |
127 |
HashMap<const void*, ptrdiff_t> m_ptrToOffsetMap; |
128 |
}; |
129 |
|
130 |
class Decoder { |
131 |
WTF_MAKE_NONCOPYABLE(Decoder); |
132 |
|
133 |
public: |
134 |
Decoder(VM& vm, const void* baseAddress, size_t size) |
135 |
: m_vm(vm) |
136 |
, m_baseAddress(reinterpret_cast<const uint8_t*>(baseAddress)) |
137 |
#ifndef NDEBUG |
138 |
, m_size(size) |
139 |
#endif |
140 |
{ |
141 |
UNUSED_PARAM(size); |
142 |
} |
143 |
|
144 |
~Decoder() |
145 |
{ |
146 |
for (auto& pair : m_finalizers) |
147 |
pair.value(); |
148 |
} |
149 |
|
150 |
VM& vm() { return m_vm; } |
151 |
|
152 |
ptrdiff_t offsetOf(const void* ptr) |
153 |
{ |
154 |
const uint8_t* addr = static_cast<const uint8_t*>(ptr); |
155 |
ASSERT(addr >= m_baseAddress && addr < m_baseAddress + m_size); |
156 |
return addr - m_baseAddress; |
157 |
} |
158 |
|
159 |
void cacheOffset(ptrdiff_t offset, void* ptr) |
160 |
{ |
161 |
m_offsetToPtrMap.add(offset, ptr); |
162 |
} |
163 |
|
164 |
std::optional<void*> ptrForOffset(ptrdiff_t offset) |
165 |
{ |
166 |
auto it = m_offsetToPtrMap.find(offset); |
167 |
if (it == m_offsetToPtrMap.end()) |
168 |
return std::nullopt; |
169 |
return { it->value }; |
170 |
} |
171 |
|
172 |
template<typename Functor> |
173 |
void addFinalizer(ptrdiff_t offset, const Functor& fn) |
174 |
{ |
175 |
m_finalizers.add(offset, fn); |
176 |
} |
177 |
|
178 |
private: |
179 |
VM& m_vm; |
180 |
const uint8_t* m_baseAddress; |
181 |
#ifndef NDEBUG |
182 |
size_t m_size; |
183 |
#endif |
184 |
HashMap<ptrdiff_t, void*> m_offsetToPtrMap; |
185 |
HashMap<ptrdiff_t, std::function<void()>> m_finalizers; |
186 |
}; |
187 |
|
188 |
template<typename T> |
189 |
static std::enable_if_t<std::is_same<T, SourceType<T>>::value> encode(Encoder&, T& dst, const SourceType<T>& src) |
190 |
{ |
191 |
dst = src; |
192 |
} |
193 |
|
194 |
template<typename T> |
195 |
static std::enable_if_t<!std::is_same<T, SourceType<T>>::value> encode(Encoder& encoder, T& dst, const SourceType<T>& src) |
196 |
{ |
197 |
dst.encode(encoder, src); |
198 |
} |
199 |
|
200 |
template<typename T, typename... Args> |
201 |
static std::enable_if_t<std::is_same<T, SourceType<T>>::value> decode(Decoder&, const T& src, SourceType<T>& dst, Args...) |
202 |
{ |
203 |
dst = src; |
204 |
} |
205 |
|
206 |
template<typename T, typename... Args> |
207 |
static std::enable_if_t<!std::is_same<T, SourceType<T>>::value> decode(Decoder& decoder, const T& src, SourceType<T>& dst, Args... args) |
208 |
{ |
209 |
src.decode(decoder, dst, args...); |
210 |
} |
211 |
|
212 |
template<typename T> |
213 |
static std::enable_if_t<std::is_same<T, SourceType<T>>::value, T> decode(Decoder&, T src) |
214 |
{ |
215 |
return src; |
216 |
} |
217 |
|
218 |
template<typename T> |
219 |
static std::enable_if_t<!std::is_same<T, SourceType<T>>::value, SourceType<T>>&& decode(Decoder& decoder, const T& src) |
220 |
{ |
221 |
return src.decode(decoder); |
222 |
} |
223 |
|
224 |
template<typename Source, typename Dst> |
225 |
struct CachedObject { |
226 |
using SourceType = Source; |
227 |
|
228 |
static unsigned sizeOf(const Source& source) |
229 |
{ |
230 |
unsigned size = 0; |
231 |
computeOutOfLineSize(size, source); |
232 |
return size; |
233 |
} |
234 |
|
235 |
template<typename T> |
236 |
static T& cast(T* source) |
237 |
{ |
238 |
return *source; |
239 |
} |
240 |
|
241 |
template<typename T, typename = std::enable_if_t<!std::is_pointer<T>::value>> |
242 |
static T& cast(T& source) |
243 |
{ |
244 |
return source; |
245 |
} |
246 |
|
247 |
template<typename T> |
248 |
static const T& cast(const T* const source) |
249 |
{ |
250 |
return *source; |
251 |
} |
252 |
|
253 |
template<typename T, typename = std::enable_if_t<!std::is_pointer<T>::value>> |
254 |
static const T& cast(const T& source) |
255 |
{ |
256 |
return source; |
257 |
} |
258 |
}; |
259 |
|
260 |
template<typename Source, typename Dst> |
261 |
struct VariableLengthObject : public CachedObject<Source, Dst> { |
262 |
private: |
263 |
constexpr static ptrdiff_t s_invalidOffset = PTRDIFF_MAX; |
264 |
public: |
265 |
ptrdiff_t offset { s_invalidOffset }; |
266 |
|
267 |
const uint8_t* buffer() const |
268 |
{ |
269 |
ASSERT(offset != s_invalidOffset); |
270 |
return reinterpret_cast<const uint8_t*>(this) + offset; |
271 |
} |
272 |
|
273 |
uint8_t* buffer() |
274 |
{ |
275 |
ASSERT(offset != s_invalidOffset); |
276 |
return reinterpret_cast<uint8_t*>(this) + offset; |
277 |
} |
278 |
|
279 |
template<typename T> |
280 |
const T* buffer() const |
281 |
{ |
282 |
return reinterpret_cast<const T*>(buffer()); |
283 |
} |
284 |
|
285 |
template<typename T> |
286 |
T* buffer() |
287 |
{ |
288 |
return reinterpret_cast<T*>(buffer()); |
289 |
} |
290 |
|
291 |
uint8_t* allocate(Encoder& encoder, size_t size) |
292 |
{ |
293 |
ptrdiff_t offsetOffset = encoder.offsetOf(&offset); |
294 |
ptrdiff_t allocationOffset = encoder.mallocOffset(size); |
295 |
offset = allocationOffset - offsetOffset; |
296 |
return buffer(); |
297 |
} |
298 |
|
299 |
template<typename T> |
300 |
T* allocate(Encoder& encoder, unsigned size = 1) |
301 |
{ |
302 |
allocate(encoder, sizeof(T[size])); |
303 |
return buffer<T>(); |
304 |
} |
305 |
}; |
306 |
|
307 |
template<typename T, typename SourceType = SourceType<T>> |
308 |
struct CachedPtr : public VariableLengthObject<SourceType*, CachedPtr<T>> { |
309 |
bool isEmpty; |
310 |
|
311 |
void encode(Encoder& encoder, const SourceType* src) |
312 |
{ |
313 |
isEmpty = !src; |
314 |
if (isEmpty) |
315 |
return; |
316 |
|
317 |
if (std::optional<ptrdiff_t> offset = encoder.offsetForPtr(src)) { |
318 |
this->offset = *offset - encoder.offsetOf(&this->offset); |
319 |
return; |
320 |
} |
321 |
|
322 |
T* cachedObject = this->template allocate<T>(encoder); |
323 |
cachedObject->encode(encoder, *src); |
324 |
encoder.cachePtr(src, encoder.offsetOf(cachedObject)); |
325 |
} |
326 |
|
327 |
template<typename... Args> |
328 |
SourceType* decode(Decoder& decoder, Args... args) const |
329 |
{ |
330 |
if (isEmpty) |
331 |
return nullptr; |
332 |
|
333 |
ptrdiff_t bufferOffset = decoder.offsetOf(this->buffer()); |
334 |
if (std::optional<void*> ptr = decoder.ptrForOffset(bufferOffset)) |
335 |
return reinterpret_cast<SourceType*>(*ptr); |
336 |
|
337 |
SourceType* ptr = operator->()->decode(decoder, args...); |
338 |
decoder.cacheOffset(bufferOffset, ptr); |
339 |
return ptr; |
340 |
} |
341 |
|
342 |
T* operator->() |
343 |
{ |
344 |
if (isEmpty) |
345 |
return nullptr; |
346 |
return this->template buffer<T>(); |
347 |
} |
348 |
|
349 |
const T* operator->() const |
350 |
{ |
351 |
if (isEmpty) |
352 |
return nullptr; |
353 |
return this->template buffer<T>(); |
354 |
} |
355 |
}; |
356 |
|
357 |
template<typename T, typename SourceType = SourceType<T>> |
358 |
struct CachedRefPtr : public CachedObject<RefPtr<SourceType>, CachedRefPtr<T>> { |
359 |
CachedPtr<T, SourceType> ptr; |
360 |
|
361 |
void encode(Encoder& encoder, const SourceType* src) |
362 |
{ |
363 |
ptr.encode(encoder, src); |
364 |
} |
365 |
|
366 |
void encode(Encoder& encoder, const RefPtr<SourceType> src) |
367 |
{ |
368 |
encode(encoder, src.get()); |
369 |
} |
370 |
|
371 |
RefPtr<SourceType> decode(Decoder& decoder) const |
372 |
{ |
373 |
SourceType* decodedPtr = ptr.decode(decoder); |
374 |
decoder.addFinalizer(decoder.offsetOf(ptr.buffer()), [=] { derefIfNotNull(decodedPtr); }); |
375 |
refIfNotNull(decodedPtr); |
376 |
return adoptRef(decodedPtr); |
377 |
} |
378 |
|
379 |
void decode(Decoder& decoder, RefPtr<SourceType>& src) const |
380 |
{ |
381 |
src = decode(decoder); |
382 |
} |
383 |
}; |
384 |
|
385 |
template<typename T, typename SourceType = SourceType<T>> |
386 |
struct CachedWriteBarrier : public CachedObject<WriteBarrier<SourceType>, CachedWriteBarrier<T>> { |
387 |
CachedPtr<T, SourceType> ptr; |
388 |
|
389 |
void encode(Encoder& encoder, const WriteBarrier<SourceType> src) |
390 |
{ |
391 |
ptr.encode(encoder, src.get()); |
392 |
} |
393 |
|
394 |
void decode(Decoder& decoder, WriteBarrier<SourceType>& src, const JSCell* owner) const |
395 |
{ |
396 |
SourceType* decodedPtr = ptr.decode(decoder); |
397 |
if (decodedPtr) |
398 |
src.set(decoder.vm(), owner, decodedPtr); |
399 |
} |
400 |
}; |
401 |
|
402 |
template<typename T, size_t IC = 0, typename OH = CrashOnOverflow> |
403 |
struct CachedVector : public VariableLengthObject<Vector<SourceType<T>, IC, OH>, CachedVector<T, IC, OH>> { |
404 |
unsigned size; |
405 |
|
406 |
void encode(Encoder& encoder, const Vector<SourceType<T>, IC, OH>& vector) |
407 |
{ |
408 |
size = vector.size(); |
409 |
T* buffer = this->template allocate<T>(encoder, size); |
410 |
for (unsigned i = 0; i < size; ++i) |
411 |
::JSC::encode(encoder, buffer[i], vector[i]); |
412 |
} |
413 |
|
414 |
template<typename... Args> |
415 |
void decode(Decoder& decoder, Vector<SourceType<T>, IC, OH>& vector, Args... args) const |
416 |
{ |
417 |
vector.resizeToFit(size); |
418 |
const T* buffer = this->template buffer<T>(); |
419 |
for (unsigned i = 0; i < size; ++i) |
420 |
::JSC::decode(decoder, buffer[i], vector[i], args...); |
421 |
} |
422 |
}; |
423 |
|
424 |
template<typename Fst, typename Snd> |
425 |
struct CachedPair : public CachedObject<std::pair<SourceType<Fst>, SourceType<Snd>>, CachedPair<Fst, Snd>> { |
426 |
Fst fst; |
427 |
Snd snd; |
428 |
|
429 |
void encode(Encoder& encoder, const std::pair<SourceType<Fst>, SourceType<Snd>>& pair) |
430 |
{ |
431 |
::JSC::encode(encoder, fst, std::get<0>(pair)); |
432 |
::JSC::encode(encoder, snd, std::get<1>(pair)); |
433 |
} |
434 |
|
435 |
void decode(Decoder& decoder, std::pair<SourceType<Fst>, SourceType<Snd>>& pair) const |
436 |
{ |
437 |
::JSC::decode(decoder, fst, std::get<0>(pair)); |
438 |
::JSC::decode(decoder, snd, std::get<1>(pair)); |
439 |
} |
440 |
}; |
441 |
|
442 |
template<typename Key, typename Value, typename HashArg = typename DefaultHash<SourceType<Key>>::Hash, typename KeyTraitsArg = HashTraits<SourceType<Key>>, typename MappedTraitsArg = HashTraits<SourceType<Value>>> |
443 |
struct CachedHashMap : public VariableLengthObject<HashMap<SourceType<Key>, SourceType<Value>, HashArg, KeyTraitsArg, MappedTraitsArg>, CachedHashMap<Key, Value, HashArg, KeyTraitsArg, MappedTraitsArg>> { |
444 |
|
445 |
CachedVector<CachedPair<Key, Value>> entries; |
446 |
|
447 |
template<typename K, typename V> |
448 |
using Map = HashMap<K, V, HashArg, KeyTraitsArg, MappedTraitsArg>; |
449 |
|
450 |
void encode(Encoder& encoder, const Map<SourceType<Key>, SourceType<Value>>& map) |
451 |
{ |
452 |
entries.size = map.size(); |
453 |
SourceType<decltype(entries)> entriesVector(map.size()); |
454 |
unsigned i = 0; |
455 |
for (const auto& it : map) |
456 |
entriesVector[i++] = { it.key, it.value }; |
457 |
entries.encode(encoder, entriesVector); |
458 |
} |
459 |
|
460 |
void decode(Decoder& decoder, Map<SourceType<Key>, SourceType<Value>>& map) const |
461 |
{ |
462 |
SourceType<decltype(entries)> decodedEntries; |
463 |
entries.decode(decoder, decodedEntries); |
464 |
for (const auto& pair : decodedEntries) |
465 |
map.set(std::get<0>(pair), std::get<1>(pair)); |
466 |
} |
467 |
}; |
468 |
|
469 |
struct CachedUniquedStringImpl : public VariableLengthObject<UniquedStringImpl, CachedUniquedStringImpl> { |
470 |
bool is8Bit : 1; |
471 |
bool isSymbol : 1; |
472 |
bool isAtomic : 1; |
473 |
unsigned length; |
474 |
|
475 |
void encode(Encoder& encoder, const StringImpl& string) |
476 |
{ |
477 |
isAtomic = string.isAtomic(); |
478 |
isSymbol = string.isSymbol(); |
479 |
StringImpl* impl = const_cast<StringImpl*>(&string); |
480 |
if (isSymbol) { |
481 |
SymbolImpl* symbol = static_cast<SymbolImpl*>(impl); |
482 |
if (!symbol->isNullSymbol()) { |
483 |
Identifier uid = Identifier::fromUid(&encoder.vm(), symbol); |
484 |
impl = encoder.vm().propertyNames->lookUpPublicName(uid).string().impl(); |
485 |
} |
486 |
} |
487 |
|
488 |
is8Bit = impl->is8Bit(); |
489 |
length = impl->length(); |
490 |
|
491 |
if (!length) |
492 |
return; |
493 |
|
494 |
unsigned size = length; |
495 |
const void* payload; |
496 |
if (is8Bit) |
497 |
payload = impl->characters8(); |
498 |
else { |
499 |
payload = impl->characters16(); |
500 |
size *= 2; |
501 |
} |
502 |
|
503 |
uint8_t* buffer = this->allocate(encoder, size); |
504 |
memcpy(buffer, payload, size); |
505 |
} |
506 |
|
507 |
UniquedStringImpl* decode(Decoder& decoder) const |
508 |
{ |
509 |
auto create = [&](const auto* buffer) -> UniquedStringImpl* { |
510 |
if (!isSymbol) |
511 |
return AtomicStringImpl::add(buffer, length).leakRef(); |
512 |
|
513 |
if (!length) |
514 |
return &SymbolImpl::createNullSymbol().leakRef(); |
515 |
|
516 |
Identifier ident = Identifier::fromString(&decoder.vm(), buffer, length); |
517 |
String str = decoder.vm().propertyNames->lookUpPrivateName(ident)->string(); |
518 |
StringImpl* impl = str.releaseImpl().get(); |
519 |
ASSERT(impl->isSymbol()); |
520 |
return static_cast<UniquedStringImpl*>(impl); |
521 |
}; |
522 |
|
523 |
if (is8Bit) |
524 |
return create(this->buffer<LChar>()); |
525 |
return create(this->buffer<UChar>()); |
526 |
} |
527 |
}; |
528 |
|
529 |
struct CachedStringImpl : public VariableLengthObject<StringImpl, CachedStringImpl> { |
530 |
CachedUniquedStringImpl uniquedStringImpl; |
531 |
|
532 |
void encode(Encoder& encoder, const StringImpl& impl) |
533 |
{ |
534 |
uniquedStringImpl.encode(encoder, impl); |
535 |
} |
536 |
|
537 |
StringImpl* decode(Decoder& decoder) const |
538 |
{ |
539 |
return uniquedStringImpl.decode(decoder); |
540 |
} |
541 |
}; |
542 |
|
543 |
struct CachedString : public VariableLengthObject<String, CachedString> { |
544 |
CachedRefPtr<CachedUniquedStringImpl> impl; |
545 |
|
546 |
void encode(Encoder& encoder, const String& string) |
547 |
{ |
548 |
impl.encode(encoder, static_cast<UniquedStringImpl*>(string.impl())); |
549 |
} |
550 |
|
551 |
String decode(Decoder& decoder) const |
552 |
{ |
553 |
return String((RefPtr<StringImpl>)impl.decode(decoder)); |
554 |
} |
555 |
|
556 |
void decode(Decoder& decoder, String& dst) const |
557 |
{ |
558 |
dst = decode(decoder); |
559 |
} |
560 |
}; |
561 |
|
562 |
struct CachedIdentifier : public VariableLengthObject<Identifier, CachedIdentifier> { |
563 |
CachedString string; |
564 |
|
565 |
void encode(Encoder& encoder, const Identifier& identifier) |
566 |
{ |
567 |
string.encode(encoder, identifier.string()); |
568 |
} |
569 |
|
570 |
Identifier decode(Decoder& decoder) const |
571 |
{ |
572 |
String str = string.decode(decoder); |
573 |
if (str.isNull()) |
574 |
return Identifier(); |
575 |
|
576 |
return Identifier::fromUid(&decoder.vm(), (UniquedStringImpl*)str.impl()); |
577 |
} |
578 |
|
579 |
void decode(Decoder& decoder, Identifier& ident) const |
580 |
{ |
581 |
ident = decode(decoder); |
582 |
} |
583 |
}; |
584 |
|
585 |
template<typename T> |
586 |
struct CachedOptional : public VariableLengthObject<std::optional<SourceType<T>>, CachedOptional<T>> { |
587 |
bool isEmpty; |
588 |
|
589 |
void encode(Encoder& encoder, const std::optional<SourceType<T>>& source) |
590 |
{ |
591 |
isEmpty = !source; |
592 |
|
593 |
if (isEmpty) |
594 |
return; |
595 |
|
596 |
this->template allocate<T>(encoder)->encode(encoder, *source); |
597 |
} |
598 |
|
599 |
std::optional<SourceType<T>> decode(Decoder& decoder) const |
600 |
{ |
601 |
if (isEmpty) |
602 |
return std::nullopt; |
603 |
|
604 |
return { this->template buffer<T>()->decode(decoder) }; |
605 |
} |
606 |
|
607 |
void decode(Decoder& decoder, std::optional<SourceType<T>>& dst) const |
608 |
{ |
609 |
dst = decode(decoder); |
610 |
} |
611 |
|
612 |
void encode(Encoder& encoder, const std::unique_ptr<SourceType<T>>& source) |
613 |
{ |
614 |
if (!source) |
615 |
encode(encoder, std::nullopt); |
616 |
else |
617 |
encode(encoder, { *source }); |
618 |
} |
619 |
|
620 |
SourceType<T>* decodeAsPtr(Decoder& decoder) const |
621 |
{ |
622 |
if (isEmpty) |
623 |
return nullptr; |
624 |
|
625 |
return this->template buffer<T>()->decode(decoder); |
626 |
} |
627 |
}; |
628 |
|
629 |
struct CachedSimpleJumpTable : public CachedObject<UnlinkedSimpleJumpTable, CachedSimpleJumpTable> { |
630 |
int32_t min; |
631 |
CachedVector<int32_t> branchOffsets; |
632 |
|
633 |
void encode(Encoder& encoder, const UnlinkedSimpleJumpTable& jumpTable) |
634 |
{ |
635 |
min = jumpTable.min; |
636 |
branchOffsets.encode(encoder, jumpTable.branchOffsets); |
637 |
} |
638 |
|
639 |
void decode(Decoder& decoder, UnlinkedSimpleJumpTable& jumpTable) const |
640 |
{ |
641 |
jumpTable.min = min; |
642 |
branchOffsets.decode(decoder, jumpTable.branchOffsets); |
643 |
} |
644 |
}; |
645 |
|
646 |
struct CachedStringJumpTable : public CachedObject<UnlinkedStringJumpTable, CachedStringJumpTable> { |
647 |
CachedHashMap<CachedRefPtr<CachedStringImpl>, UnlinkedStringJumpTable:: OffsetLocation> offsetTable; |
648 |
|
649 |
void encode(Encoder& encoder, const UnlinkedStringJumpTable& jumpTable) |
650 |
{ |
651 |
offsetTable.encode(encoder, jumpTable.offsetTable); |
652 |
} |
653 |
|
654 |
void decode(Decoder& decoder, UnlinkedStringJumpTable& jumpTable) const |
655 |
{ |
656 |
offsetTable.decode(decoder, jumpTable.offsetTable); |
657 |
} |
658 |
}; |
659 |
|
660 |
struct CachedRareData : public CachedObject<UnlinkedCodeBlock::RareData, CachedRareData> { |
661 |
CachedVector<UnlinkedHandlerInfo> exceptionHandlers; |
662 |
|
663 |
// Jump Tables |
664 |
CachedVector<CachedSimpleJumpTable> switchJumpTables; |
665 |
CachedVector<CachedStringJumpTable> stringSwitchJumpTables; |
666 |
|
667 |
CachedVector<ExpressionRangeInfo::FatPosition> expressionInfoFatPositions; |
668 |
|
669 |
CachedHashMap<unsigned, UnlinkedCodeBlock::RareData::TypeProfilerExpressionRange> typeProfilerInfoMap; |
670 |
CachedVector<InstructionStream::Offset> opProfileControlFlowBytecodeOffsets; |
671 |
|
672 |
|
673 |
void encode(Encoder& encoder, const UnlinkedCodeBlock::RareData& rareData) |
674 |
{ |
675 |
exceptionHandlers.encode(encoder, rareData.m_exceptionHandlers); |
676 |
switchJumpTables.encode(encoder, rareData.m_switchJumpTables); |
677 |
stringSwitchJumpTables.encode(encoder, rareData.m_stringSwitchJumpTables); |
678 |
expressionInfoFatPositions.encode(encoder, rareData.m_expressionInfoFatPositions); |
679 |
typeProfilerInfoMap.encode(encoder, rareData.m_typeProfilerInfoMap); |
680 |
opProfileControlFlowBytecodeOffsets.encode(encoder, rareData.m_opProfileControlFlowBytecodeOffsets); |
681 |
} |
682 |
|
683 |
UnlinkedCodeBlock::RareData* decode(Decoder& decoder) const |
684 |
{ |
685 |
UnlinkedCodeBlock::RareData* rareData = new UnlinkedCodeBlock::RareData { }; |
686 |
exceptionHandlers.decode(decoder, rareData->m_exceptionHandlers); |
687 |
switchJumpTables.decode(decoder, rareData->m_switchJumpTables); |
688 |
stringSwitchJumpTables.decode(decoder, rareData->m_stringSwitchJumpTables); |
689 |
expressionInfoFatPositions.decode(decoder, rareData->m_expressionInfoFatPositions); |
690 |
typeProfilerInfoMap.decode(decoder, rareData->m_typeProfilerInfoMap); |
691 |
opProfileControlFlowBytecodeOffsets.decode(decoder, rareData->m_opProfileControlFlowBytecodeOffsets); |
692 |
return rareData; |
693 |
} |
694 |
|
695 |
}; |
696 |
|
697 |
struct CachedBitVector : public VariableLengthObject<BitVector, CachedBitVector> { |
698 |
unsigned size; |
699 |
|
700 |
void encode(Encoder& encoder, const BitVector& bitVector) |
701 |
{ |
702 |
size = bitVector.size(); |
703 |
uint8_t* buffer = this->allocate(encoder, size); |
704 |
memcpy(buffer, bitVector.bits(), size); |
705 |
} |
706 |
|
707 |
void decode(Decoder&, BitVector& bitVector) const |
708 |
{ |
709 |
bitVector.ensureSize(size); |
710 |
memcpy(bitVector.bits(), this->buffer(), size); |
711 |
} |
712 |
}; |
713 |
|
714 |
template<typename T, typename HashArg = typename DefaultHash<T>::Hash> |
715 |
struct CachedHashSet : public CachedObject<HashSet<SourceType<T>, HashArg>, CachedHashSet<T, HashArg>> { |
716 |
CachedVector<T> entries; |
717 |
|
718 |
void encode(Encoder& encoder, const HashSet<SourceType<T>, HashArg>& set) |
719 |
{ |
720 |
SourceType<decltype(entries)> entriesVector(set.size()); |
721 |
unsigned i = 0; |
722 |
for (const auto& item : set) |
723 |
entriesVector[i++] = item; |
724 |
entries.encode(encoder, entriesVector); |
725 |
} |
726 |
|
727 |
void decode(Decoder& decoder, HashSet<SourceType<T>, HashArg>& set) const |
728 |
{ |
729 |
SourceType<decltype(entries)> entriesVector; |
730 |
entries.decode(decoder, entriesVector); |
731 |
for (const auto& item : entriesVector) |
732 |
set.add(item); |
733 |
} |
734 |
}; |
735 |
|
736 |
struct CachedConstantIdentifierSetEntry : public VariableLengthObject<ConstantIdentifierSetEntry, CachedConstantIdentifierSetEntry> { |
737 |
unsigned constant; |
738 |
CachedHashSet<CachedRefPtr<CachedUniquedStringImpl>, IdentifierRepHash> set; |
739 |
|
740 |
void encode(Encoder& encoder, const ConstantIdentifierSetEntry& entry) |
741 |
{ |
742 |
constant = std::get<1>(entry); |
743 |
set.encode(encoder, std::get<0>(entry)); |
744 |
} |
745 |
|
746 |
void decode(Decoder& decoder, ConstantIdentifierSetEntry& entry) const |
747 |
{ |
748 |
std::get<1>(entry) = constant; |
749 |
set.decode(decoder, std::get<0>(entry)); |
750 |
} |
751 |
}; |
752 |
|
753 |
struct CachedVariableEnvironment : public CachedObject<VariableEnvironment, CachedVariableEnvironment> { |
754 |
|
755 |
bool isEverythingCaptured; |
756 |
CachedHashMap<CachedRefPtr<CachedUniquedStringImpl>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> map; |
757 |
|
758 |
void encode(Encoder& encoder, const VariableEnvironment& env) |
759 |
{ |
760 |
isEverythingCaptured = env.m_isEverythingCaptured; |
761 |
map.encode(encoder, env.m_map); |
762 |
} |
763 |
|
764 |
void decode(Decoder& decoder, VariableEnvironment& env) const |
765 |
{ |
766 |
env.m_isEverythingCaptured = isEverythingCaptured; |
767 |
map.decode(decoder, env.m_map); |
768 |
} |
769 |
}; |
770 |
|
771 |
template<typename T, typename SourceType = SourceType<T>> |
772 |
struct CachedArray : public VariableLengthObject<SourceType*, CachedArray<T, SourceType>> { |
773 |
void encode(Encoder& encoder, const SourceType* array, unsigned size) |
774 |
{ |
775 |
T* dst = this->template allocate<T>(encoder, size); |
776 |
for (unsigned i = 0; i < size; ++i) |
777 |
::JSC::encode(encoder, dst[i], array[i]); |
778 |
} |
779 |
|
780 |
template<typename... Args> |
781 |
void decode(Decoder& decoder, SourceType* array, unsigned size, Args... args) const |
782 |
{ |
783 |
const T* buffer = this->template buffer<T>(); |
784 |
for (unsigned i = 0; i < size; ++i) |
785 |
::JSC::decode(decoder, buffer[i], array[i], args...); |
786 |
} |
787 |
}; |
788 |
|
789 |
struct CachedScopedArgumentsTable : public CachedObject<ScopedArgumentsTable, CachedScopedArgumentsTable> { |
790 |
uint32_t length; |
791 |
CachedArray<ScopeOffset> arguments; |
792 |
|
793 |
void encode(Encoder& encoder, const ScopedArgumentsTable& scopedArgumentsTable) |
794 |
{ |
795 |
length = scopedArgumentsTable.m_length; |
796 |
arguments.encode(encoder, scopedArgumentsTable.m_arguments.get(), length); |
797 |
} |
798 |
|
799 |
ScopedArgumentsTable* decode(Decoder& decoder) const |
800 |
{ |
801 |
ScopedArgumentsTable* scopedArgumentsTable = ScopedArgumentsTable::create(decoder.vm(), length); |
802 |
arguments.decode(decoder, scopedArgumentsTable->m_arguments.get(), length); |
803 |
return scopedArgumentsTable; |
804 |
} |
805 |
}; |
806 |
|
807 |
struct CachedSymbolTableEntry : public CachedObject<SymbolTableEntry, CachedSymbolTableEntry> { |
808 |
intptr_t bits; |
809 |
|
810 |
void encode(Encoder&, const SymbolTableEntry& symbolTableEntry) |
811 |
{ |
812 |
bits = symbolTableEntry.m_bits | SymbolTableEntry::SlimFlag; |
813 |
} |
814 |
|
815 |
void decode(Decoder&, SymbolTableEntry& symbolTableEntry) const |
816 |
{ |
817 |
symbolTableEntry.m_bits = bits; |
818 |
} |
819 |
}; |
820 |
|
821 |
struct CachedSymbolTable : public CachedObject<SymbolTable, CachedSymbolTable> { |
822 |
CachedHashMap<CachedRefPtr<CachedUniquedStringImpl>, CachedSymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, SymbolTableIndexHashTraits> map; |
823 |
ScopeOffset maxScopeOffset; |
824 |
unsigned usesNonStrictEval : 1; |
825 |
unsigned nestedLexicalScope : 1; |
826 |
unsigned scopeType : 3; |
827 |
// FIXME: do we need to cached this eventually? |
828 |
// CachedPtr<SymbolTableRareData> rareData; |
829 |
CachedPtr<CachedScopedArgumentsTable> arguments; |
830 |
|
831 |
void encode(Encoder& encoder, const SymbolTable& symbolTable) |
832 |
{ |
833 |
ASSERT(!symbolTable.m_rareData); |
834 |
map.encode(encoder, symbolTable.m_map); |
835 |
maxScopeOffset = symbolTable.m_maxScopeOffset; |
836 |
usesNonStrictEval = symbolTable.m_usesNonStrictEval; |
837 |
nestedLexicalScope = symbolTable.m_nestedLexicalScope; |
838 |
scopeType = symbolTable.m_scopeType; |
839 |
arguments.encode(encoder, symbolTable.m_arguments.get()); |
840 |
} |
841 |
|
842 |
SymbolTable* decode(Decoder& decoder) const |
843 |
{ |
844 |
SymbolTable* symbolTable = SymbolTable::create(decoder.vm()); |
845 |
map.decode(decoder, symbolTable->m_map); |
846 |
symbolTable->m_maxScopeOffset = maxScopeOffset; |
847 |
symbolTable->m_usesNonStrictEval = usesNonStrictEval; |
848 |
symbolTable->m_nestedLexicalScope = nestedLexicalScope; |
849 |
symbolTable->m_scopeType = scopeType; |
850 |
ScopedArgumentsTable* scopedArgumentsTable = arguments.decode(decoder); |
851 |
if (scopedArgumentsTable) |
852 |
symbolTable->m_arguments.set(decoder.vm(), symbolTable, scopedArgumentsTable); |
853 |
return symbolTable; |
854 |
} |
855 |
}; |
856 |
|
857 |
struct CachedJSValue; |
858 |
struct CachedImmutableButterfly : public CachedObject<JSImmutableButterfly, CachedImmutableButterfly> { |
859 |
IndexingType indexingType; |
860 |
unsigned length; |
861 |
union { |
862 |
CachedArray<double> cachedDoubles; |
863 |
CachedArray<CachedJSValue, WriteBarrier<Unknown>> cachedValues; |
864 |
}; |
865 |
|
866 |
void encode(Encoder& encoder, JSImmutableButterfly& immutableButterfly) |
867 |
{ |
868 |
length = immutableButterfly.length(); |
869 |
indexingType = immutableButterfly.indexingMode(); // this is confusing, not sure why we have to use indexingMode vs indexingType |
870 |
if (hasDouble(indexingType)) |
871 |
cachedDoubles.encode(encoder, immutableButterfly.toButterfly()->contiguousDouble().data(), length); |
872 |
else |
873 |
cachedValues.encode(encoder, immutableButterfly.toButterfly()->contiguous().data(), length); |
874 |
} |
875 |
|
876 |
JSImmutableButterfly* decode(Decoder& decoder) const |
877 |
{ |
878 |
JSImmutableButterfly* immutableButterfly = JSImmutableButterfly::create(decoder.vm(), indexingType, length); |
879 |
if (hasDouble(indexingType)) |
880 |
cachedDoubles.decode(decoder, immutableButterfly->toButterfly()->contiguousDouble().data(), length, immutableButterfly); |
881 |
else |
882 |
cachedValues.decode(decoder, immutableButterfly->toButterfly()->contiguous().data(), length, immutableButterfly); |
883 |
return immutableButterfly; |
884 |
} |
885 |
}; |
886 |
|
887 |
struct CachedRegExp : public CachedObject<RegExp, CachedRegExp> { |
888 |
CachedString patternString; |
889 |
RegExpFlags flags; |
890 |
|
891 |
void encode(Encoder& encoder, const RegExp& regExp) |
892 |
{ |
893 |
patternString.encode(encoder, regExp.m_patternString); |
894 |
flags = regExp.m_flags; |
895 |
} |
896 |
|
897 |
RegExp* decode(Decoder& decoder) const |
898 |
{ |
899 |
String pattern { patternString.decode(decoder) }; |
900 |
return RegExp::create(decoder.vm(), pattern, flags); |
901 |
} |
902 |
}; |
903 |
|
904 |
struct CachedTemplateObjectDescriptor : public CachedObject<TemplateObjectDescriptor, CachedTemplateObjectDescriptor> { |
905 |
CachedVector<CachedString, 4> rawStrings; |
906 |
CachedVector<CachedOptional<CachedString>, 4> cookedStrings; |
907 |
|
908 |
void encode(Encoder& encoder, const TemplateObjectDescriptor& templateObjectDescriptor) |
909 |
{ |
910 |
rawStrings.encode(encoder, templateObjectDescriptor.rawStrings()); |
911 |
cookedStrings.encode(encoder, templateObjectDescriptor.cookedStrings()); |
912 |
} |
913 |
|
914 |
Ref<TemplateObjectDescriptor> decode(Decoder& decoder) const |
915 |
{ |
916 |
TemplateObjectDescriptor::StringVector decodedRawStrings; |
917 |
TemplateObjectDescriptor::OptionalStringVector decodedCookedStrings; |
918 |
rawStrings.decode(decoder, decodedRawStrings); |
919 |
cookedStrings.decode(decoder, decodedCookedStrings); |
920 |
return TemplateObjectDescriptor::create(WTFMove(decodedRawStrings), WTFMove(decodedCookedStrings)); |
921 |
} |
922 |
}; |
923 |
|
924 |
struct CachedBigInt : public VariableLengthObject<JSBigInt, CachedBigInt> { |
925 |
unsigned length; |
926 |
bool sign; |
927 |
|
928 |
void encode(Encoder& encoder, JSBigInt& bigInt) |
929 |
{ |
930 |
length = bigInt.length(); |
931 |
sign = bigInt.sign(); |
932 |
|
933 |
if (!length) |
934 |
return; |
935 |
|
936 |
unsigned size = sizeof(JSBigInt::Digit[length]); |
937 |
this->allocate(encoder, size); |
938 |
memcpy(this->buffer(), bigInt.dataStorage(), size); |
939 |
} |
940 |
|
941 |
JSBigInt* decode(Decoder& decoder) const |
942 |
{ |
943 |
JSBigInt* bigInt = JSBigInt::createWithLength(decoder.vm(), length); |
944 |
bigInt->setSign(sign); |
945 |
memcpy(bigInt->dataStorage(), this->buffer(), sizeof(JSBigInt::Digit[length])); |
946 |
return bigInt; |
947 |
} |
948 |
}; |
949 |
|
950 |
struct CachedJSValue : public VariableLengthObject<WriteBarrier<Unknown>, CachedJSValue> { |
951 |
enum class EncodedType : uint8_t { |
952 |
JSValue, |
953 |
SymbolTable, |
954 |
String, |
955 |
ImmutableButterfly, |
956 |
RegExp, |
957 |
TemplateObjectDescriptor, |
958 |
BigInt, |
959 |
}; |
960 |
|
961 |
EncodedType type; |
962 |
|
963 |
void encode(Encoder& encoder, const WriteBarrier<Unknown> value) |
964 |
{ |
965 |
JSValue v = value.get(); |
966 |
|
967 |
if (!v.isCell() || v.isEmpty()) { |
968 |
type = EncodedType::JSValue; |
969 |
*this->allocate<EncodedJSValue>(encoder) = JSValue::encode(v); |
970 |
return; |
971 |
} |
972 |
|
973 |
JSCell* cell = v.asCell(); |
974 |
const ClassInfo* classInfo = cell->classInfo(encoder.vm()); |
975 |
|
976 |
if (classInfo == SymbolTable::info()) { |
977 |
type = EncodedType::SymbolTable; |
978 |
this->allocate<CachedSymbolTable>(encoder)->encode(encoder, *jsCast<SymbolTable*>(cell)); |
979 |
return; |
980 |
} |
981 |
|
982 |
if (classInfo == JSString::info()) { |
983 |
type = EncodedType::String; |
984 |
StringImpl* impl = asString(cell)->tryGetValue().impl(); |
985 |
ASSERT(!impl || !impl->isSymbol()); |
986 |
this->allocate<CachedUniquedStringImpl>(encoder)->encode(encoder, *impl); |
987 |
return; |
988 |
} |
989 |
|
990 |
if (classInfo == JSImmutableButterfly::info()) { |
991 |
type = EncodedType::ImmutableButterfly; |
992 |
this->allocate<CachedImmutableButterfly>(encoder)->encode(encoder, *jsCast<JSImmutableButterfly*>(cell)); |
993 |
return; |
994 |
} |
995 |
|
996 |
if (classInfo == RegExp::info()) { |
997 |
type = EncodedType::RegExp; |
998 |
this->allocate<CachedRegExp>(encoder)->encode(encoder, *jsCast<RegExp*>(cell)); |
999 |
return; |
1000 |
} |
1001 |
|
1002 |
if (classInfo == JSTemplateObjectDescriptor::info()) { |
1003 |
type = EncodedType::TemplateObjectDescriptor; |
1004 |
this->allocate<CachedTemplateObjectDescriptor>(encoder)->encode(encoder, jsCast<JSTemplateObjectDescriptor*>(cell)->descriptor()); |
1005 |
return; |
1006 |
} |
1007 |
|
1008 |
if (classInfo == JSBigInt::info()) { |
1009 |
type = EncodedType::BigInt; |
1010 |
this->allocate<CachedBigInt>(encoder)->encode(encoder, *jsCast<JSBigInt*>(cell)); |
1011 |
return; |
1012 |
} |
1013 |
|
1014 |
RELEASE_ASSERT_NOT_REACHED(); |
1015 |
} |
1016 |
|
1017 |
void decode(Decoder& decoder, WriteBarrier<Unknown>& value, const JSCell* owner) const |
1018 |
{ |
1019 |
JSValue v; |
1020 |
switch (type) { |
1021 |
case EncodedType::JSValue: |
1022 |
v = JSValue::decode(*this->buffer<EncodedJSValue>()); |
1023 |
break; |
1024 |
case EncodedType::SymbolTable: |
1025 |
v = this->buffer<CachedSymbolTable>()->decode(decoder); |
1026 |
break; |
1027 |
case EncodedType::String: { |
1028 |
UniquedStringImpl* impl = this->buffer<CachedUniquedStringImpl>()->decode(decoder); |
1029 |
v = JSString::create(decoder.vm(), adoptRef(*impl)); |
1030 |
break; |
1031 |
} |
1032 |
case EncodedType::ImmutableButterfly: |
1033 |
v = this->buffer<CachedImmutableButterfly>()->decode(decoder); |
1034 |
break; |
1035 |
case EncodedType::RegExp: |
1036 |
v = this->buffer<CachedRegExp>()->decode(decoder); |
1037 |
break; |
1038 |
case EncodedType::TemplateObjectDescriptor: |
1039 |
v = JSTemplateObjectDescriptor::create(decoder.vm(), this->buffer<CachedTemplateObjectDescriptor>()->decode(decoder)); |
1040 |
break; |
1041 |
case EncodedType::BigInt: |
1042 |
v = this->buffer<CachedBigInt>()->decode(decoder); |
1043 |
break; |
1044 |
default: |
1045 |
RELEASE_ASSERT_NOT_REACHED(); |
1046 |
} |
1047 |
value.set(decoder.vm(), owner, v); |
1048 |
} |
1049 |
}; |
1050 |
|
1051 |
struct CachedInstructionStream : public CachedObject<InstructionStream, CachedInstructionStream> { |
1052 |
CachedVector<uint8_t, 0, UnsafeVectorOverflow> instructions; |
1053 |
|
1054 |
void encode(Encoder& encoder, const InstructionStream& stream) |
1055 |
{ |
1056 |
instructions.encode(encoder, stream.m_instructions); |
1057 |
} |
1058 |
|
1059 |
InstructionStream* decode(Decoder& decoder) const |
1060 |
{ |
1061 |
Vector<uint8_t, 0, UnsafeVectorOverflow> instructionsVector; |
1062 |
instructions.decode(decoder, instructionsVector); |
1063 |
return new InstructionStream(WTFMove(instructionsVector)); |
1064 |
} |
1065 |
}; |
1066 |
|
1067 |
struct CachedMetadataTable : public CachedObject<UnlinkedMetadataTable, CachedMetadataTable> { |
1068 |
bool hasMetadata; |
1069 |
std::array<unsigned, UnlinkedMetadataTable::s_offsetTableEntries> metadata; |
1070 |
|
1071 |
void encode(Encoder&, const UnlinkedMetadataTable& metadataTable) |
1072 |
{ |
1073 |
ASSERT(metadataTable.m_isFinalized); |
1074 |
hasMetadata = metadataTable.m_hasMetadata; |
1075 |
if (!hasMetadata) |
1076 |
return; |
1077 |
for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) |
1078 |
metadata[i] = metadataTable.m_buffer[i]; |
1079 |
} |
1080 |
|
1081 |
void decode(Decoder&, UnlinkedMetadataTable& metadataTable) const |
1082 |
{ |
1083 |
metadataTable.m_isFinalized = true; |
1084 |
metadataTable.m_isLinked = false; |
1085 |
metadataTable.m_hasMetadata = hasMetadata; |
1086 |
for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) |
1087 |
metadataTable.m_buffer[i] = metadata[i]; |
1088 |
} |
1089 |
}; |
1090 |
|
1091 |
struct CachedSourceOrigin : public CachedObject<SourceOrigin, CachedSourceOrigin> { |
1092 |
CachedString string; |
1093 |
|
1094 |
void encode(Encoder& encoder, const SourceOrigin& sourceOrigin) |
1095 |
{ |
1096 |
string.encode(encoder, sourceOrigin.string()); |
1097 |
} |
1098 |
|
1099 |
SourceOrigin decode(Decoder& decoder) const |
1100 |
{ |
1101 |
return SourceOrigin { string.decode(decoder) }; |
1102 |
} |
1103 |
}; |
1104 |
|
1105 |
struct CachedTextPosition : public CachedObject<TextPosition, CachedTextPosition> { |
1106 |
int line; |
1107 |
int column; |
1108 |
|
1109 |
void encode(Encoder&, TextPosition textPosition) |
1110 |
{ |
1111 |
line = textPosition.m_line.zeroBasedInt(); |
1112 |
column = textPosition.m_column.zeroBasedInt(); |
1113 |
} |
1114 |
|
1115 |
TextPosition decode(Decoder&) const |
1116 |
{ |
1117 |
return TextPosition { OrdinalNumber::fromZeroBasedInt(line), OrdinalNumber::fromZeroBasedInt(column) }; |
1118 |
} |
1119 |
}; |
1120 |
|
1121 |
template <typename SourceType, typename CachedType> |
1122 |
struct CachedSourceProviderShape : public CachedObject<SourceType, CachedType> { |
1123 |
bool validated : 1; |
1124 |
CachedSourceOrigin sourceOrigin; |
1125 |
CachedString url; |
1126 |
CachedString sourceURLDirective; |
1127 |
CachedString sourceMappingURLDirective; |
1128 |
CachedTextPosition startPosition; |
1129 |
|
1130 |
void encode(Encoder& encoder, const SourceProvider& sourceProvider) |
1131 |
{ |
1132 |
validated = sourceProvider.isValid(); |
1133 |
sourceOrigin.encode(encoder, sourceProvider.sourceOrigin()); |
1134 |
url.encode(encoder, sourceProvider.url()); |
1135 |
sourceURLDirective.encode(encoder, sourceProvider.sourceURL()); |
1136 |
sourceMappingURLDirective.encode(encoder, sourceProvider.sourceMappingURL()); |
1137 |
startPosition.encode(encoder, sourceProvider.startPosition()); |
1138 |
} |
1139 |
|
1140 |
void decode(Decoder& decoder, SourceProvider& sourceProvider) const |
1141 |
{ |
1142 |
if (validated) |
1143 |
sourceProvider.setValid(); |
1144 |
sourceProvider.setSourceURLDirective(sourceURLDirective.decode(decoder)); |
1145 |
sourceProvider.setSourceMappingURLDirective(sourceMappingURLDirective.decode(decoder)); |
1146 |
} |
1147 |
}; |
1148 |
|
1149 |
struct CachedStringSourceProvider : public CachedSourceProviderShape<StringSourceProvider, CachedStringSourceProvider> { |
1150 |
using Base = CachedSourceProviderShape<StringSourceProvider, CachedStringSourceProvider>; |
1151 |
|
1152 |
CachedString source; |
1153 |
|
1154 |
void encode(Encoder& encoder, const StringSourceProvider& sourceProvider) |
1155 |
{ |
1156 |
Base::encode(encoder, sourceProvider); |
1157 |
source.encode(encoder, sourceProvider.source().toString()); |
1158 |
} |
1159 |
|
1160 |
StringSourceProvider* decode(Decoder& decoder, SourceProviderSourceType sourceType) const |
1161 |
{ |
1162 |
String decodedSource = source.decode(decoder); |
1163 |
SourceOrigin decodedSourceOrigin = sourceOrigin.decode(decoder); |
1164 |
String decodedURL = url.decode(decoder); |
1165 |
TextPosition decodedStartPosition = startPosition.decode(decoder); |
1166 |
|
1167 |
Ref<StringSourceProvider> sourceProvider = StringSourceProvider::create(decodedSource, decodedSourceOrigin, decodedURL, decodedStartPosition, sourceType); |
1168 |
Base::decode(decoder, sourceProvider.get()); |
1169 |
return &sourceProvider.leakRef(); |
1170 |
} |
1171 |
}; |
1172 |
|
1173 |
#if ENABLE(WEBASSEMBLY) |
1174 |
struct CachedWebAssemblySourceProvider : public CachedSourceProviderShape<WebAssemblySourceProvider, CachedWebAssemblySourceProvider> { |
1175 |
using Base = CachedSourceProviderShape<WebAssemblySourceProvider, CachedWebAssemblySourceProvider>; |
1176 |
|
1177 |
CachedVector<uint8_t> data; |
1178 |
|
1179 |
void encode(Encoder& encoder, const WebAssemblySourceProvider& sourceProvider) |
1180 |
{ |
1181 |
Base::encode(encoder, sourceProvider); |
1182 |
data.encode(encoder, sourceProvider.data()); |
1183 |
} |
1184 |
|
1185 |
WebAssemblySourceProvider* decode(Decoder& decoder) const |
1186 |
{ |
1187 |
Vector<uint8_t> decodedData; |
1188 |
SourceOrigin decodedSourceOrigin = sourceOrigin.decode(decoder); |
1189 |
String decodedURL = url.decode(decoder); |
1190 |
|
1191 |
data.decode(decoder, decodedData); |
1192 |
|
1193 |
Ref<WebAssemblySourceProvider> sourceProvider = WebAssemblySourceProvider::create(WTFMove(decodedData), decodedSourceOrigin, decodedURL); |
1194 |
Base::decode(decoder, sourceProvider.get()); |
1195 |
|
1196 |
return &sourceProvider.leakRef(); |
1197 |
} |
1198 |
}; |
1199 |
#endif |
1200 |
|
1201 |
struct CachedSourceProvider : public VariableLengthObject<SourceProvider, CachedSourceProvider> { |
1202 |
SourceProviderSourceType sourceType; |
1203 |
|
1204 |
void encode(Encoder& encoder, const SourceProvider& sourceProvider) |
1205 |
{ |
1206 |
sourceType = sourceProvider.sourceType(); |
1207 |
switch (sourceType) { |
1208 |
case SourceProviderSourceType::Program: |
1209 |
case SourceProviderSourceType::Module: |
1210 |
this->allocate<CachedStringSourceProvider>(encoder)->encode(encoder, reinterpret_cast<const StringSourceProvider&>(sourceProvider)); |
1211 |
break; |
1212 |
#if ENABLE(WEBASSEMBLY) |
1213 |
case SourceProviderSourceType::WebAssembly: |
1214 |
this->allocate<CachedWebAssemblySourceProvider>(encoder)->encode(encoder, reinterpret_cast<const WebAssemblySourceProvider&>(sourceProvider)); |
1215 |
break; |
1216 |
#endif |
1217 |
default: |
1218 |
RELEASE_ASSERT_NOT_REACHED(); |
1219 |
} |
1220 |
} |
1221 |
|
1222 |
SourceProvider* decode(Decoder& decoder) const |
1223 |
{ |
1224 |
switch (sourceType) { |
1225 |
case SourceProviderSourceType::Program: |
1226 |
case SourceProviderSourceType::Module: |
1227 |
return this->buffer<CachedStringSourceProvider>()->decode(decoder, sourceType); |
1228 |
#if ENABLE(WEBASSEMBLY) |
1229 |
case SourceProviderSourceType::WebAssembly: |
1230 |
return this->buffer<CachedWebAssemblySourceProvider>()->decode(decoder); |
1231 |
#endif |
1232 |
default: |
1233 |
RELEASE_ASSERT_NOT_REACHED(); |
1234 |
} |
1235 |
} |
1236 |
}; |
1237 |
|
1238 |
template<typename SourceType, typename CacheType> |
1239 |
struct CachedUnlinkedSourceCodeShape : public CachedObject<SourceType, CacheType> { |
1240 |
CachedPtr<CachedSourceProvider> provider; |
1241 |
int startOffset; |
1242 |
int endOffset; |
1243 |
|
1244 |
void encode(Encoder& encoder, const UnlinkedSourceCode& sourceCode) |
1245 |
{ |
1246 |
provider.encode(encoder, sourceCode.m_provider.get()); |
1247 |
startOffset = sourceCode.startOffset(); |
1248 |
endOffset = sourceCode.endOffset(); |
1249 |
} |
1250 |
|
1251 |
void decode(Decoder& decoder, UnlinkedSourceCode& sourceCode) const |
1252 |
{ |
1253 |
sourceCode.m_provider = provider.decode(decoder); |
1254 |
sourceCode.m_startOffset = startOffset; |
1255 |
sourceCode.m_endOffset = endOffset; |
1256 |
} |
1257 |
}; |
1258 |
|
1259 |
|
1260 |
struct CachedUnlinkedSourceCode : public CachedUnlinkedSourceCodeShape<UnlinkedSourceCode, CachedUnlinkedSourceCode> { }; |
1261 |
|
1262 |
struct CachedSourceCode : public CachedUnlinkedSourceCodeShape<SourceCode, CachedSourceCode> { |
1263 |
using Base = CachedUnlinkedSourceCodeShape<SourceCode, CachedSourceCode>; |
1264 |
|
1265 |
int firstLine; |
1266 |
int startColumn; |
1267 |
|
1268 |
void encode(Encoder& encoder, const SourceCode& sourceCode) |
1269 |
{ |
1270 |
Base::encode(encoder, sourceCode); |
1271 |
firstLine = sourceCode.firstLine().zeroBasedInt(); |
1272 |
startColumn = sourceCode.startColumn().zeroBasedInt(); |
1273 |
} |
1274 |
|
1275 |
void decode(Decoder& decoder, SourceCode& sourceCode) const |
1276 |
{ |
1277 |
Base::decode(decoder, sourceCode); |
1278 |
sourceCode.m_firstLine = OrdinalNumber::fromZeroBasedInt(firstLine); |
1279 |
sourceCode.m_startColumn = OrdinalNumber::fromZeroBasedInt(startColumn); |
1280 |
} |
1281 |
}; |
1282 |
|
1283 |
struct CachedFunctionExecutable : public CachedObject<UnlinkedFunctionExecutable, CachedFunctionExecutable> { |
1284 |
|
1285 |
void encode(Encoder&, const UnlinkedFunctionExecutable&); |
1286 |
UnlinkedFunctionExecutable* decode(Decoder&) const; |
1287 |
|
1288 |
unsigned firstLineOffset; |
1289 |
unsigned lineCount; |
1290 |
unsigned unlinkedFunctionNameStart; |
1291 |
unsigned unlinkedBodyStartColumn; |
1292 |
unsigned unlinkedBodyEndColumn; |
1293 |
unsigned startOffset; |
1294 |
unsigned sourceLength; |
1295 |
unsigned parametersStartOffset; |
1296 |
unsigned typeProfilingStartOffset; |
1297 |
unsigned typeProfilingEndOffset; |
1298 |
unsigned parameterCount; |
1299 |
CodeFeatures features; |
1300 |
SourceParseMode sourceParseMode; |
1301 |
unsigned isInStrictContext : 1; |
1302 |
unsigned hasCapturedVariables : 1; |
1303 |
unsigned isBuiltinFunction : 1; |
1304 |
unsigned isBuiltinDefaultClassConstructor : 1; |
1305 |
unsigned constructAbility: 1; |
1306 |
unsigned constructorKind : 2; |
1307 |
unsigned functionMode : 2; // FunctionMode |
1308 |
unsigned scriptMode: 1; // JSParserScriptMode |
1309 |
unsigned superBinding : 1; |
1310 |
unsigned derivedContextType: 2; |
1311 |
|
1312 |
CachedSourceCode classSource; |
1313 |
|
1314 |
CachedIdentifier name; |
1315 |
CachedIdentifier ecmaName; |
1316 |
CachedIdentifier inferredName; |
1317 |
|
1318 |
CachedVariableEnvironment parentScopeTDZVariables; |
1319 |
|
1320 |
CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> unlinkedCodeBlockForCall; |
1321 |
CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> unlinkedCodeBlockForConstruct; |
1322 |
}; |
1323 |
|
1324 |
template<typename CodeBlockType, typename CachedCodeBlockType> |
1325 |
struct CachedCodeBlock : public CachedObject<CodeBlockType, CachedCodeBlockType> { |
1326 |
void encode(Encoder&, const UnlinkedCodeBlock&); |
1327 |
void decode(Decoder&, UnlinkedCodeBlock&) const; |
1328 |
|
1329 |
VirtualRegister thisRegister; |
1330 |
VirtualRegister scopeRegister; |
1331 |
VirtualRegister globalObjectRegister; |
1332 |
|
1333 |
unsigned usesEval : 1; |
1334 |
unsigned isStrictMode : 1; |
1335 |
unsigned isConstructor : 1; |
1336 |
unsigned hasCapturedVariables : 1; |
1337 |
unsigned isBuiltinFunction : 1; |
1338 |
unsigned superBinding : 1; |
1339 |
unsigned scriptMode: 1; |
1340 |
unsigned isArrowFunctionContext : 1; |
1341 |
unsigned isClassContext : 1; |
1342 |
unsigned wasCompiledWithDebuggingOpcodes : 1; |
1343 |
unsigned constructorKind : 2; |
1344 |
unsigned derivedContextType : 2; |
1345 |
unsigned evalContextType : 2; |
1346 |
unsigned hasTailCalls : 1; |
1347 |
|
1348 |
unsigned lineCount; |
1349 |
unsigned endColumn; |
1350 |
|
1351 |
int numVars; |
1352 |
int numCalleeLocals; |
1353 |
int numParameters; |
1354 |
|
1355 |
CodeFeatures features; |
1356 |
SourceParseMode parseMode; |
1357 |
CodeType codeType; |
1358 |
|
1359 |
std::array<unsigned, LinkTimeConstantCount> linkTimeConstants; |
1360 |
CachedMetadataTable metadata; |
1361 |
|
1362 |
CachedOptional<CachedRareData> rareData; |
1363 |
|
1364 |
CachedString sourceURLDirective; |
1365 |
CachedString sourceMappingURLDirective; |
1366 |
|
1367 |
CachedPtr<CachedInstructionStream> instructions; |
1368 |
CachedVector<InstructionStream::Offset> jumpTargets; |
1369 |
CachedVector<InstructionStream::Offset> propertyAccessInstructions; |
1370 |
CachedVector<CachedJSValue> constantRegisters; |
1371 |
CachedVector<SourceCodeRepresentation> constantsSourceCodeRepresentation; |
1372 |
CachedVector<ExpressionRangeInfo> expressionInfo; |
1373 |
CachedHashMap<InstructionStream::Offset, int> outOfLineJumpTargets; |
1374 |
|
1375 |
CachedVector<CachedConstantIdentifierSetEntry> constantIdentifierSets; |
1376 |
CachedVector<CachedIdentifier> identifiers; |
1377 |
CachedVector<CachedBitVector> bitVectors; |
1378 |
CachedVector<CachedWriteBarrier<CachedFunctionExecutable>> functionDecls; |
1379 |
CachedVector<CachedWriteBarrier<CachedFunctionExecutable>> functionExprs; |
1380 |
}; |
1381 |
|
1382 |
struct CachedProgramCodeBlock : public CachedCodeBlock<UnlinkedProgramCodeBlock, CachedProgramCodeBlock> { |
1383 |
using Base = CachedCodeBlock<UnlinkedProgramCodeBlock, CachedProgramCodeBlock>; |
1384 |
using Base::encode; |
1385 |
|
1386 |
CachedVariableEnvironment varDeclarations; |
1387 |
CachedVariableEnvironment lexicalDeclarations; |
1388 |
|
1389 |
void encode(Encoder& encoder, const UnlinkedProgramCodeBlock& codeBlock) |
1390 |
{ |
1391 |
Base::encode(encoder, codeBlock); |
1392 |
varDeclarations.encode(encoder, codeBlock.m_varDeclarations); |
1393 |
lexicalDeclarations.encode(encoder, codeBlock.m_lexicalDeclarations); |
1394 |
} |
1395 |
|
1396 |
UnlinkedProgramCodeBlock* decode(Decoder& decoder) const |
1397 |
{ |
1398 |
UnlinkedProgramCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedProgramCodeBlock>(decoder.vm().heap)) UnlinkedProgramCodeBlock(decoder, *this); |
1399 |
codeBlock->finishCreation(decoder.vm()); |
1400 |
Base::decode(decoder, *codeBlock); |
1401 |
varDeclarations.decode(decoder, codeBlock->m_varDeclarations); |
1402 |
lexicalDeclarations.decode(decoder, codeBlock->m_lexicalDeclarations); |
1403 |
return codeBlock; |
1404 |
} |
1405 |
}; |
1406 |
|
1407 |
struct CachedModuleCodeBlock : public CachedCodeBlock<UnlinkedModuleProgramCodeBlock, CachedModuleCodeBlock> { |
1408 |
using Base = CachedCodeBlock<UnlinkedModuleProgramCodeBlock, CachedModuleCodeBlock>; |
1409 |
using Base::encode; |
1410 |
|
1411 |
int moduleEnvironmentSymbolTableConstantRegisterOffset; |
1412 |
|
1413 |
void encode(Encoder& encoder, const UnlinkedModuleProgramCodeBlock& codeBlock) |
1414 |
{ |
1415 |
Base::encode(encoder, codeBlock); |
1416 |
moduleEnvironmentSymbolTableConstantRegisterOffset = codeBlock.m_moduleEnvironmentSymbolTableConstantRegisterOffset; |
1417 |
} |
1418 |
|
1419 |
UnlinkedModuleProgramCodeBlock* decode(Decoder& decoder) const |
1420 |
{ |
1421 |
UnlinkedModuleProgramCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedModuleProgramCodeBlock>(decoder.vm().heap)) UnlinkedModuleProgramCodeBlock(decoder, *this); |
1422 |
codeBlock->finishCreation(decoder.vm()); |
1423 |
Base::decode(decoder, *codeBlock); |
1424 |
codeBlock->m_moduleEnvironmentSymbolTableConstantRegisterOffset = moduleEnvironmentSymbolTableConstantRegisterOffset; |
1425 |
return codeBlock; |
1426 |
} |
1427 |
}; |
1428 |
|
1429 |
struct CachedEvalCodeBlock : public CachedCodeBlock<UnlinkedEvalCodeBlock, CachedEvalCodeBlock> { |
1430 |
using Base = CachedCodeBlock<UnlinkedEvalCodeBlock, CachedEvalCodeBlock>; |
1431 |
using Base::encode; |
1432 |
|
1433 |
CachedVector<CachedIdentifier, 0, UnsafeVectorOverflow> variables; |
1434 |
CachedVector<CachedIdentifier, 0, UnsafeVectorOverflow> functionHoistingCandidates; |
1435 |
|
1436 |
void encode(Encoder& encoder, const UnlinkedEvalCodeBlock& codeBlock) |
1437 |
{ |
1438 |
Base::encode(encoder, codeBlock); |
1439 |
variables.encode(encoder, codeBlock.m_variables); |
1440 |
functionHoistingCandidates.encode(encoder, codeBlock.m_functionHoistingCandidates); |
1441 |
} |
1442 |
|
1443 |
UnlinkedEvalCodeBlock* decode(Decoder& decoder) const |
1444 |
{ |
1445 |
UnlinkedEvalCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedEvalCodeBlock>(decoder.vm().heap)) UnlinkedEvalCodeBlock(decoder, *this); |
1446 |
codeBlock->finishCreation(decoder.vm()); |
1447 |
Base::decode(decoder, *codeBlock); |
1448 |
variables.decode(decoder, codeBlock->m_variables); |
1449 |
functionHoistingCandidates.decode(decoder, codeBlock->m_functionHoistingCandidates); |
1450 |
return codeBlock; |
1451 |
} |
1452 |
}; |
1453 |
|
1454 |
struct CachedFunctionCodeBlock : public CachedCodeBlock<UnlinkedFunctionCodeBlock, CachedFunctionCodeBlock> { |
1455 |
using Base = CachedCodeBlock<UnlinkedFunctionCodeBlock, CachedFunctionCodeBlock>; |
1456 |
|
1457 |
void encode(Encoder& encoder, const UnlinkedFunctionCodeBlock& codeBlock) |
1458 |
{ |
1459 |
Base::encode(encoder, codeBlock); |
1460 |
} |
1461 |
|
1462 |
UnlinkedFunctionCodeBlock* decode(Decoder& decoder) const |
1463 |
{ |
1464 |
UnlinkedFunctionCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedFunctionCodeBlock>(decoder.vm().heap)) UnlinkedFunctionCodeBlock(decoder, *this); |
1465 |
codeBlock->finishCreation(decoder.vm()); |
1466 |
Base::decode(decoder, *codeBlock); |
1467 |
return codeBlock; |
1468 |
} |
1469 |
}; |
1470 |
|
1471 |
ALWAYS_INLINE UnlinkedFunctionCodeBlock::UnlinkedFunctionCodeBlock(Decoder& decoder, const CachedFunctionCodeBlock& cachedCodeBlock) |
1472 |
: Base(decoder, decoder.vm().unlinkedFunctionCodeBlockStructure.get(), cachedCodeBlock) |
1473 |
{ |
1474 |
} |
1475 |
|
1476 |
template<typename T> |
1477 |
struct CachedCodeBlockTypeImpl; |
1478 |
|
1479 |
template<> |
1480 |
struct CachedCodeBlockTypeImpl<UnlinkedProgramCodeBlock> { |
1481 |
using type = CachedProgramCodeBlock; |
1482 |
}; |
1483 |
|
1484 |
template<> |
1485 |
struct CachedCodeBlockTypeImpl<UnlinkedModuleProgramCodeBlock> { |
1486 |
using type = CachedModuleCodeBlock; |
1487 |
}; |
1488 |
|
1489 |
template<> |
1490 |
struct CachedCodeBlockTypeImpl<UnlinkedEvalCodeBlock> { |
1491 |
using type = CachedEvalCodeBlock; |
1492 |
}; |
1493 |
|
1494 |
template<typename T> |
1495 |
using CachedCodeBlockType = typename CachedCodeBlockTypeImpl<T>::type; |
1496 |
|
1497 |
template<typename CodeBlockType, typename CachedCodeBlockType> |
1498 |
ALWAYS_INLINE UnlinkedCodeBlock::UnlinkedCodeBlock(Decoder& decoder, Structure* structure, const CachedCodeBlock<CodeBlockType, CachedCodeBlockType>& cachedCodeBlock) |
1499 |
: Base(decoder.vm(), structure) |
1500 |
, m_instructions(cachedCodeBlock.instructions.decode(decoder)) |
1501 |
, m_liveness(nullptr) |
1502 |
, m_thisRegister(cachedCodeBlock.thisRegister) |
1503 |
, m_scopeRegister(cachedCodeBlock.scopeRegister) |
1504 |
, m_globalObjectRegister(cachedCodeBlock.globalObjectRegister) |
1505 |
|
1506 |
, m_sourceURLDirective(cachedCodeBlock.sourceURLDirective.decode(decoder)) |
1507 |
, m_sourceMappingURLDirective(cachedCodeBlock.sourceMappingURLDirective.decode(decoder)) |
1508 |
|
1509 |
, m_usesEval(cachedCodeBlock.usesEval) |
1510 |
, m_isStrictMode(cachedCodeBlock.isStrictMode) |
1511 |
, m_isConstructor(cachedCodeBlock.isConstructor) |
1512 |
, m_hasCapturedVariables(cachedCodeBlock.hasCapturedVariables) |
1513 |
, m_isBuiltinFunction(cachedCodeBlock.isBuiltinFunction) |
1514 |
, m_superBinding(cachedCodeBlock.superBinding) |
1515 |
, m_scriptMode(cachedCodeBlock.scriptMode) |
1516 |
, m_isArrowFunctionContext(cachedCodeBlock.isArrowFunctionContext) |
1517 |
, m_isClassContext(cachedCodeBlock.isClassContext) |
1518 |
, m_wasCompiledWithDebuggingOpcodes(cachedCodeBlock.wasCompiledWithDebuggingOpcodes) |
1519 |
, m_constructorKind(cachedCodeBlock.constructorKind) |
1520 |
, m_derivedContextType(cachedCodeBlock.derivedContextType) |
1521 |
, m_evalContextType(cachedCodeBlock.evalContextType) |
1522 |
, m_hasTailCalls(cachedCodeBlock.hasTailCalls) |
1523 |
, m_lineCount(cachedCodeBlock.lineCount) |
1524 |
, m_endColumn(cachedCodeBlock.endColumn) |
1525 |
, m_numVars(cachedCodeBlock.numVars) |
1526 |
, m_numCalleeLocals(cachedCodeBlock.numCalleeLocals) |
1527 |
, m_numParameters(cachedCodeBlock.numParameters) |
1528 |
, m_features(cachedCodeBlock.features) |
1529 |
, m_parseMode(cachedCodeBlock.parseMode) |
1530 |
, m_codeType(cachedCodeBlock.codeType) |
1531 |
, m_rareData(cachedCodeBlock.rareData.decodeAsPtr(decoder)) |
1532 |
{ |
1533 |
} |
1534 |
|
1535 |
template<typename CodeBlockType, typename CachedCodeBlockType> |
1536 |
ALWAYS_INLINE void CachedCodeBlock<CodeBlockType, CachedCodeBlockType>::decode(Decoder& decoder, UnlinkedCodeBlock& codeBlock) const |
1537 |
{ |
1538 |
for (unsigned i = LinkTimeConstantCount; i--;) |
1539 |
codeBlock.m_linkTimeConstants[i] = linkTimeConstants[i]; |
1540 |
|
1541 |
metadata.decode(decoder, codeBlock.m_metadata); |
1542 |
propertyAccessInstructions.decode(decoder, codeBlock.m_propertyAccessInstructions); |
1543 |
constantRegisters.decode(decoder, codeBlock.m_constantRegisters, &codeBlock); |
1544 |
constantsSourceCodeRepresentation.decode(decoder, codeBlock.m_constantsSourceCodeRepresentation); |
1545 |
expressionInfo.decode(decoder, codeBlock.m_expressionInfo); |
1546 |
outOfLineJumpTargets.decode(decoder, codeBlock.m_outOfLineJumpTargets); |
1547 |
jumpTargets.decode(decoder, codeBlock.m_jumpTargets); |
1548 |
constantIdentifierSets.decode(decoder, codeBlock.m_constantIdentifierSets); |
1549 |
identifiers.decode(decoder, codeBlock.m_identifiers); |
1550 |
bitVectors.decode(decoder, codeBlock.m_bitVectors); |
1551 |
functionDecls.decode(decoder, codeBlock.m_functionDecls, &codeBlock); |
1552 |
functionExprs.decode(decoder, codeBlock.m_functionExprs, &codeBlock); |
1553 |
} |
1554 |
|
1555 |
ALWAYS_INLINE UnlinkedProgramCodeBlock::UnlinkedProgramCodeBlock(Decoder& decoder, const CachedProgramCodeBlock& cachedCodeBlock) |
1556 |
: Base(decoder, decoder.vm().unlinkedProgramCodeBlockStructure.get(), cachedCodeBlock) |
1557 |
{ |
1558 |
} |
1559 |
|
1560 |
ALWAYS_INLINE UnlinkedModuleProgramCodeBlock::UnlinkedModuleProgramCodeBlock(Decoder& decoder, const CachedModuleCodeBlock& cachedCodeBlock) |
1561 |
: Base(decoder, decoder.vm().unlinkedModuleProgramCodeBlockStructure.get(), cachedCodeBlock) |
1562 |
{ |
1563 |
} |
1564 |
|
1565 |
ALWAYS_INLINE UnlinkedEvalCodeBlock::UnlinkedEvalCodeBlock(Decoder& decoder, const CachedEvalCodeBlock& cachedCodeBlock) |
1566 |
: Base(decoder, decoder.vm().unlinkedEvalCodeBlockStructure.get(), cachedCodeBlock) |
1567 |
{ |
1568 |
} |
1569 |
|
1570 |
/////////// |
1571 |
|
1572 |
ALWAYS_INLINE void CachedFunctionExecutable::encode(Encoder& encoder, const UnlinkedFunctionExecutable& executable) |
1573 |
{ |
1574 |
firstLineOffset = executable.m_firstLineOffset; |
1575 |
lineCount = executable.m_lineCount; |
1576 |
unlinkedFunctionNameStart = executable.m_unlinkedFunctionNameStart; |
1577 |
unlinkedBodyStartColumn = executable.m_unlinkedBodyStartColumn; |
1578 |
unlinkedBodyEndColumn = executable.m_unlinkedBodyEndColumn; |
1579 |
startOffset = executable.m_startOffset; |
1580 |
sourceLength = executable.m_sourceLength; |
1581 |
parametersStartOffset = executable.m_parametersStartOffset; |
1582 |
typeProfilingStartOffset = executable.m_typeProfilingStartOffset; |
1583 |
typeProfilingEndOffset = executable.m_typeProfilingEndOffset; |
1584 |
parameterCount = executable.m_parameterCount; |
1585 |
|
1586 |
features = executable.m_features; |
1587 |
sourceParseMode = executable.m_sourceParseMode; |
1588 |
|
1589 |
isInStrictContext = executable.m_isInStrictContext; |
1590 |
hasCapturedVariables = executable.m_hasCapturedVariables; |
1591 |
isBuiltinFunction = executable.m_isBuiltinFunction; |
1592 |
isBuiltinDefaultClassConstructor = executable.m_isBuiltinDefaultClassConstructor; |
1593 |
constructAbility = executable.m_constructAbility; |
1594 |
constructorKind = executable.m_constructorKind; |
1595 |
functionMode = executable.m_functionMode; |
1596 |
scriptMode = executable.m_scriptMode; |
1597 |
superBinding = executable.m_superBinding; |
1598 |
derivedContextType = executable.m_derivedContextType; |
1599 |
|
1600 |
classSource.encode(encoder, executable.m_classSource); |
1601 |
|
1602 |
name.encode(encoder, executable.name()); |
1603 |
ecmaName.encode(encoder, executable.ecmaName()); |
1604 |
inferredName.encode(encoder, executable.inferredName()); |
1605 |
|
1606 |
parentScopeTDZVariables.encode(encoder, executable.parentScopeTDZVariables()); |
1607 |
|
1608 |
unlinkedCodeBlockForCall.encode(encoder, executable.m_unlinkedCodeBlockForCall); |
1609 |
unlinkedCodeBlockForConstruct.encode(encoder, executable.m_unlinkedCodeBlockForConstruct); |
1610 |
} |
1611 |
|
1612 |
ALWAYS_INLINE UnlinkedFunctionExecutable* CachedFunctionExecutable::decode(Decoder& decoder) const |
1613 |
{ |
1614 |
VariableEnvironment env; |
1615 |
parentScopeTDZVariables.decode(decoder, env); |
1616 |
|
1617 |
UnlinkedFunctionExecutable* executable = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(decoder.vm().heap)) UnlinkedFunctionExecutable(decoder, env, *this); |
1618 |
executable->finishCreation(decoder.vm()); |
1619 |
|
1620 |
classSource.decode(decoder, executable->m_classSource); |
1621 |
unlinkedCodeBlockForCall.decode(decoder, executable->m_unlinkedCodeBlockForCall, executable); |
1622 |
unlinkedCodeBlockForConstruct.decode(decoder, executable->m_unlinkedCodeBlockForConstruct, executable); |
1623 |
|
1624 |
return executable; |
1625 |
} |
1626 |
|
1627 |
ALWAYS_INLINE UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(Decoder& decoder, VariableEnvironment& parentScopeTDZVariables, const CachedFunctionExecutable& cachedExecutable) |
1628 |
: Base(decoder.vm(), decoder.vm().unlinkedFunctionExecutableStructure.get()) |
1629 |
, m_firstLineOffset(cachedExecutable.firstLineOffset) |
1630 |
, m_lineCount(cachedExecutable.lineCount) |
1631 |
, m_unlinkedFunctionNameStart(cachedExecutable.unlinkedFunctionNameStart) |
1632 |
, m_unlinkedBodyStartColumn(cachedExecutable.unlinkedBodyStartColumn) |
1633 |
, m_unlinkedBodyEndColumn(cachedExecutable.unlinkedBodyEndColumn) |
1634 |
, m_startOffset(cachedExecutable.startOffset) |
1635 |
, m_sourceLength(cachedExecutable.sourceLength) |
1636 |
, m_parametersStartOffset(cachedExecutable.parametersStartOffset) |
1637 |
, m_typeProfilingStartOffset(cachedExecutable.typeProfilingStartOffset) |
1638 |
, m_typeProfilingEndOffset(cachedExecutable.typeProfilingEndOffset) |
1639 |
, m_parameterCount(cachedExecutable.parameterCount) |
1640 |
, m_features(cachedExecutable.features) |
1641 |
, m_sourceParseMode(cachedExecutable.sourceParseMode) |
1642 |
, m_isInStrictContext(cachedExecutable.isInStrictContext) |
1643 |
, m_hasCapturedVariables(cachedExecutable.hasCapturedVariables) |
1644 |
, m_isBuiltinFunction(cachedExecutable.isBuiltinFunction) |
1645 |
, m_isBuiltinDefaultClassConstructor(cachedExecutable.isBuiltinDefaultClassConstructor) |
1646 |
, m_constructAbility(cachedExecutable.constructAbility) |
1647 |
, m_constructorKind(cachedExecutable.constructorKind) |
1648 |
, m_functionMode(cachedExecutable.functionMode) |
1649 |
, m_scriptMode(cachedExecutable.scriptMode) |
1650 |
, m_superBinding(cachedExecutable.superBinding) |
1651 |
, m_derivedContextType(cachedExecutable.derivedContextType) |
1652 |
|
1653 |
, m_name(cachedExecutable.name.decode(decoder)) |
1654 |
, m_ecmaName(cachedExecutable.ecmaName.decode(decoder)) |
1655 |
, m_inferredName(cachedExecutable.inferredName.decode(decoder)) |
1656 |
|
1657 |
, m_parentScopeTDZVariables(decoder.vm().m_compactVariableMap->get(parentScopeTDZVariables)) |
1658 |
{ |
1659 |
} |
1660 |
|
1661 |
template<typename CodeBlockType, typename CachedCodeBlockType> |
1662 |
ALWAYS_INLINE void CachedCodeBlock<CodeBlockType, CachedCodeBlockType>::encode(Encoder& encoder, const UnlinkedCodeBlock& codeBlock) |
1663 |
{ |
1664 |
thisRegister = codeBlock.m_thisRegister; |
1665 |
scopeRegister = codeBlock.m_scopeRegister; |
1666 |
globalObjectRegister = codeBlock.m_globalObjectRegister; |
1667 |
usesEval = codeBlock.m_usesEval; |
1668 |
isStrictMode = codeBlock.m_isStrictMode; |
1669 |
isConstructor = codeBlock.m_isConstructor; |
1670 |
hasCapturedVariables = codeBlock.m_hasCapturedVariables; |
1671 |
isBuiltinFunction = codeBlock.m_isBuiltinFunction; |
1672 |
superBinding = codeBlock.m_superBinding; |
1673 |
scriptMode = codeBlock.m_scriptMode; |
1674 |
isArrowFunctionContext = codeBlock.m_isArrowFunctionContext; |
1675 |
isClassContext = codeBlock.m_isClassContext; |
1676 |
wasCompiledWithDebuggingOpcodes = codeBlock.m_wasCompiledWithDebuggingOpcodes; |
1677 |
constructorKind = codeBlock.m_constructorKind; |
1678 |
derivedContextType = codeBlock.m_derivedContextType; |
1679 |
evalContextType = codeBlock.m_evalContextType; |
1680 |
hasTailCalls = codeBlock.m_hasTailCalls; |
1681 |
lineCount = codeBlock.m_lineCount; |
1682 |
endColumn = codeBlock.m_endColumn; |
1683 |
numVars = codeBlock.m_numVars; |
1684 |
numCalleeLocals = codeBlock.m_numCalleeLocals; |
1685 |
numParameters = codeBlock.m_numParameters; |
1686 |
features = codeBlock.m_features; |
1687 |
parseMode = codeBlock.m_parseMode; |
1688 |
codeType = codeBlock.m_codeType; |
1689 |
|
1690 |
for (unsigned i = LinkTimeConstantCount; i--;) |
1691 |
linkTimeConstants[i] = codeBlock.m_linkTimeConstants[i]; |
1692 |
|
1693 |
metadata.encode(encoder, codeBlock.m_metadata); |
1694 |
rareData.encode(encoder, codeBlock.m_rareData); |
1695 |
|
1696 |
sourceURLDirective.encode(encoder, codeBlock.m_sourceURLDirective.impl()); |
1697 |
sourceMappingURLDirective.encode(encoder, codeBlock.m_sourceURLDirective.impl()); |
1698 |
|
1699 |
instructions.encode(encoder, codeBlock.m_instructions.get()); |
1700 |
propertyAccessInstructions.encode(encoder, codeBlock.m_propertyAccessInstructions); |
1701 |
constantRegisters.encode(encoder, codeBlock.m_constantRegisters); |
1702 |
constantsSourceCodeRepresentation.encode(encoder, codeBlock.m_constantsSourceCodeRepresentation); |
1703 |
expressionInfo.encode(encoder, codeBlock.m_expressionInfo); |
1704 |
jumpTargets.encode(encoder, codeBlock.m_jumpTargets); |
1705 |
outOfLineJumpTargets.encode(encoder, codeBlock.m_outOfLineJumpTargets); |
1706 |
|
1707 |
constantIdentifierSets.encode(encoder, codeBlock.m_constantIdentifierSets); |
1708 |
identifiers.encode(encoder, codeBlock.m_identifiers); |
1709 |
bitVectors.encode(encoder, codeBlock.m_bitVectors); |
1710 |
functionDecls.encode(encoder, codeBlock.m_functionDecls); |
1711 |
functionExprs.encode(encoder, codeBlock.m_functionExprs); |
1712 |
} |
1713 |
|
1714 |
struct CachedSourceCodeKey : public CachedObject<SourceCodeKey, CachedSourceCodeKey> { |
1715 |
CachedUnlinkedSourceCode sourceCode; |
1716 |
CachedString name; |
1717 |
unsigned flags; |
1718 |
unsigned hash; |
1719 |
|
1720 |
void encode(Encoder& encoder, const SourceCodeKey& key) |
1721 |
{ |
1722 |
sourceCode.encode(encoder, key.m_sourceCode); |
1723 |
name.encode(encoder, key.m_name); |
1724 |
flags = key.m_flags.m_flags; |
1725 |
hash = key.hash(); |
1726 |
} |
1727 |
|
1728 |
void decode(Decoder& decoder, SourceCodeKey& key) const |
1729 |
{ |
1730 |
sourceCode.decode(decoder, key.m_sourceCode); |
1731 |
name.decode(decoder, key.m_name); |
1732 |
key.m_flags.m_flags = flags; |
1733 |
key.m_hash = hash; |
1734 |
} |
1735 |
}; |
1736 |
|
1737 |
template<typename UnlinkedCodeBlockType> |
1738 |
struct CacheEntry { |
1739 |
CachedSourceCodeKey key; |
1740 |
CachedPtr<CachedCodeBlockType<UnlinkedCodeBlockType>> codeBlock; |
1741 |
|
1742 |
void encode(Encoder& encoder, std::pair<SourceCodeKey, const UnlinkedCodeBlockType*> pair) |
1743 |
{ |
1744 |
key.encode(encoder, pair.first); |
1745 |
codeBlock.encode(encoder, pair.second); |
1746 |
} |
1747 |
|
1748 |
std::pair<SourceCodeKey, UnlinkedCodeBlockType*> decode(Decoder& decoder) const |
1749 |
{ |
1750 |
SourceCodeKey decodedKey; |
1751 |
key.decode(decoder, decodedKey); |
1752 |
return { WTFMove(decodedKey), codeBlock.decode(decoder) }; |
1753 |
} |
1754 |
}; |
1755 |
|
1756 |
template<typename UnlinkedCodeBlockType> |
1757 |
ALWAYS_INLINE void encodeCodeBlock(Encoder& encoder, SourceCodeKey key, const UnlinkedCodeBlock* codeBlock) |
1758 |
{ |
1759 |
auto* entry = encoder.template malloc<CacheEntry<UnlinkedCodeBlockType>>(); |
1760 |
entry->encode(encoder, { key, jsCast<const UnlinkedCodeBlockType*>(codeBlock) }); |
1761 |
} |
1762 |
|
1763 |
ALWAYS_INLINE void encodeCodeBlock(Encoder& encoder, SourceCodeKey key, const UnlinkedCodeBlock* codeBlock) |
1764 |
{ |
1765 |
const ClassInfo* classInfo = codeBlock->classInfo(encoder.vm()); |
1766 |
|
1767 |
if (classInfo == UnlinkedProgramCodeBlock::info()) { |
1768 |
encodeCodeBlock<UnlinkedProgramCodeBlock>(encoder, key, codeBlock); |
1769 |
return; |
1770 |
} |
1771 |
|
1772 |
if (classInfo == UnlinkedModuleProgramCodeBlock::info()) { |
1773 |
encodeCodeBlock<UnlinkedModuleProgramCodeBlock>(encoder, key, codeBlock); |
1774 |
return; |
1775 |
} |
1776 |
|
1777 |
ASSERT(classInfo == UnlinkedEvalCodeBlock::info()); |
1778 |
} |
1779 |
|
1780 |
} // namespace JSC |