CachedTypes.cpp
1 /* 2 * Copyright (C) 2019-2020 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 "CachedTypes.h" 28 29 #include "BuiltinNames.h" 30 #include "BytecodeCacheError.h" 31 #include "BytecodeLivenessAnalysis.h" 32 #include "JSCInlines.h" 33 #include "JSImmutableButterfly.h" 34 #include "JSTemplateObjectDescriptor.h" 35 #include "ScopedArgumentsTable.h" 36 #include "SourceCodeKey.h" 37 #include "SourceProvider.h" 38 #include "UnlinkedEvalCodeBlock.h" 39 #include "UnlinkedFunctionCodeBlock.h" 40 #include "UnlinkedMetadataTableInlines.h" 41 #include "UnlinkedModuleProgramCodeBlock.h" 42 #include "UnlinkedProgramCodeBlock.h" 43 #include <wtf/MallocPtr.h> 44 #include <wtf/Optional.h> 45 #include <wtf/Packed.h> 46 #include <wtf/UUID.h> 47 #include <wtf/text/AtomStringImpl.h> 48 49 namespace JSC { 50 51 namespace Yarr { 52 enum class Flags : uint8_t; 53 } 54 55 template <typename T, typename = void> 56 struct SourceTypeImpl { 57 using type = T; 58 }; 59 60 template<typename T> 61 struct SourceTypeImpl<T, std::enable_if_t<!std::is_fundamental<T>::value && !std::is_same<typename T::SourceType_, void>::value>> { 62 using type = typename T::SourceType_; 63 64 }; 65 66 template<typename T> 67 using SourceType = typename SourceTypeImpl<T>::type; 68 69 static constexpr unsigned jscBytecodeCacheVersion() 70 { 71 return StringHasher::computeHash(__TIMESTAMP__); 72 } 73 74 class Encoder { 75 WTF_MAKE_NONCOPYABLE(Encoder); 76 WTF_FORBID_HEAP_ALLOCATION; 77 78 public: 79 class Allocation { 80 friend class Encoder; 81 82 public: 83 uint8_t* buffer() const { return m_buffer; } 84 ptrdiff_t offset() const { return m_offset; } 85 86 private: 87 Allocation(uint8_t* buffer, ptrdiff_t offset) 88 : m_buffer(buffer) 89 , m_offset(offset) 90 { 91 } 92 93 uint8_t* m_buffer; 94 ptrdiff_t m_offset; 95 }; 96 97 Encoder(VM& vm, FileSystem::PlatformFileHandle fd = FileSystem::invalidPlatformFileHandle) 98 : m_vm(vm) 99 , m_fd(fd) 100 , m_baseOffset(0) 101 , m_currentPage(nullptr) 102 { 103 allocateNewPage(); 104 } 105 106 VM& vm() { return m_vm; } 107 108 Allocation malloc(unsigned size) 109 { 110 RELEASE_ASSERT(size); 111 ptrdiff_t offset; 112 if (m_currentPage->malloc(size, offset)) 113 return Allocation { m_currentPage->buffer() + offset, m_baseOffset + offset }; 114 allocateNewPage(size); 115 return malloc(size); 116 } 117 118 template<typename T, typename... Args> 119 T* malloc(Args&&... args) 120 { 121 return new (malloc(sizeof(T)).buffer()) T(std::forward<Args>(args)...); 122 } 123 124 ptrdiff_t offsetOf(const void* address) 125 { 126 ptrdiff_t offset; 127 ptrdiff_t baseOffset = 0; 128 for (const auto& page : m_pages) { 129 if (page.getOffset(address, offset)) 130 return baseOffset + offset; 131 baseOffset += page.size(); 132 } 133 RELEASE_ASSERT_NOT_REACHED(); 134 return 0; 135 } 136 137 void cachePtr(const void* ptr, ptrdiff_t offset) 138 { 139 m_ptrToOffsetMap.add(ptr, offset); 140 } 141 142 Optional<ptrdiff_t> cachedOffsetForPtr(const void* ptr) 143 { 144 auto it = m_ptrToOffsetMap.find(ptr); 145 if (it == m_ptrToOffsetMap.end()) 146 return WTF::nullopt; 147 return { it->value }; 148 } 149 150 void addLeafExecutable(const UnlinkedFunctionExecutable* executable, ptrdiff_t offset) 151 { 152 m_leafExecutables.add(executable, offset); 153 } 154 155 RefPtr<CachedBytecode> release(BytecodeCacheError& error) 156 { 157 if (!m_currentPage) 158 return nullptr; 159 m_currentPage->alignEnd(); 160 161 if (FileSystem::isHandleValid(m_fd)) { 162 return releaseMapped(error); 163 } 164 165 size_t size = m_baseOffset + m_currentPage->size(); 166 MallocPtr<uint8_t, VMMalloc> buffer = MallocPtr<uint8_t, VMMalloc>::malloc(size); 167 unsigned offset = 0; 168 for (const auto& page : m_pages) { 169 memcpy(buffer.get() + offset, page.buffer(), page.size()); 170 offset += page.size(); 171 } 172 RELEASE_ASSERT(offset == size); 173 return CachedBytecode::create(WTFMove(buffer), size, WTFMove(m_leafExecutables)); 174 } 175 176 private: 177 RefPtr<CachedBytecode> releaseMapped(BytecodeCacheError& error) 178 { 179 size_t size = m_baseOffset + m_currentPage->size(); 180 if (!FileSystem::truncateFile(m_fd, size)) { 181 error = BytecodeCacheError::StandardError(errno); 182 return nullptr; 183 } 184 185 for (const auto& page : m_pages) { 186 int bytesWritten = FileSystem::writeToFile(m_fd, reinterpret_cast<char*>(page.buffer()), page.size()); 187 if (bytesWritten == -1) { 188 error = BytecodeCacheError::StandardError(errno); 189 return nullptr; 190 } 191 192 if (static_cast<size_t>(bytesWritten) != page.size()) { 193 error = BytecodeCacheError::WriteError(bytesWritten, page.size()); 194 return nullptr; 195 } 196 } 197 198 bool success; 199 FileSystem::MappedFileData mappedFileData(m_fd, FileSystem::MappedFileMode::Private, success); 200 if (!success) { 201 error = BytecodeCacheError::StandardError(errno); 202 return nullptr; 203 } 204 205 return CachedBytecode::create(WTFMove(mappedFileData), WTFMove(m_leafExecutables)); 206 } 207 208 class Page { 209 public: 210 Page(size_t size) 211 : m_buffer(MallocPtr<uint8_t, VMMalloc>::malloc(size)) 212 , m_capacity(size) 213 { 214 } 215 216 bool malloc(size_t size, ptrdiff_t& result) 217 { 218 size_t alignment = std::min(alignof(std::max_align_t), static_cast<size_t>(WTF::roundUpToPowerOfTwo(size))); 219 ptrdiff_t offset = roundUpToMultipleOf(alignment, m_offset); 220 size = roundUpToMultipleOf(alignment, size); 221 if (static_cast<size_t>(offset + size) > m_capacity) 222 return false; 223 224 result = offset; 225 m_offset = offset + size; 226 return true; 227 } 228 229 uint8_t* buffer() const { return m_buffer.get(); } 230 size_t size() const { return static_cast<size_t>(m_offset); } 231 232 bool getOffset(const void* address, ptrdiff_t& result) const 233 { 234 const uint8_t* addr = static_cast<const uint8_t*>(address); 235 if (addr >= m_buffer.get() && addr < m_buffer.get() + m_offset) { 236 result = addr - m_buffer.get(); 237 return true; 238 } 239 return false; 240 } 241 242 void alignEnd() 243 { 244 ptrdiff_t size = roundUpToMultipleOf(alignof(std::max_align_t), m_offset); 245 if (size == m_offset) 246 return; 247 RELEASE_ASSERT(static_cast<size_t>(size) <= m_capacity); 248 m_offset = size; 249 } 250 251 private: 252 MallocPtr<uint8_t, VMMalloc> m_buffer; 253 ptrdiff_t m_offset { 0 }; 254 size_t m_capacity; 255 }; 256 257 void allocateNewPage(size_t size = 0) 258 { 259 static size_t minPageSize = pageSize(); 260 if (m_currentPage) { 261 m_currentPage->alignEnd(); 262 m_baseOffset += m_currentPage->size(); 263 } 264 if (size < minPageSize) 265 size = minPageSize; 266 else 267 size = roundUpToMultipleOf(minPageSize, size); 268 m_pages.append(Page { size }); 269 m_currentPage = &m_pages.last(); 270 } 271 272 VM& m_vm; 273 FileSystem::PlatformFileHandle m_fd; 274 ptrdiff_t m_baseOffset; 275 Page* m_currentPage; 276 Vector<Page> m_pages; 277 HashMap<const void*, ptrdiff_t> m_ptrToOffsetMap; 278 LeafExecutableMap m_leafExecutables; 279 }; 280 281 Decoder::Decoder(VM& vm, Ref<CachedBytecode> cachedBytecode, RefPtr<SourceProvider> provider) 282 : m_vm(vm) 283 , m_cachedBytecode(WTFMove(cachedBytecode)) 284 , m_provider(provider) 285 { 286 } 287 288 Decoder::~Decoder() 289 { 290 for (auto& finalizer : m_finalizers) 291 finalizer(); 292 } 293 294 Ref<Decoder> Decoder::create(VM& vm, Ref<CachedBytecode> cachedBytecode, RefPtr<SourceProvider> provider) 295 { 296 return adoptRef(*new Decoder(vm, WTFMove(cachedBytecode), WTFMove(provider))); 297 } 298 299 size_t Decoder::size() const 300 { 301 return m_cachedBytecode->size(); 302 } 303 304 ptrdiff_t Decoder::offsetOf(const void* ptr) 305 { 306 const uint8_t* addr = static_cast<const uint8_t*>(ptr); 307 ASSERT(addr >= m_cachedBytecode->data() && addr < m_cachedBytecode->data() + m_cachedBytecode->size()); 308 return addr - m_cachedBytecode->data(); 309 } 310 311 void Decoder::cacheOffset(ptrdiff_t offset, void* ptr) 312 { 313 m_offsetToPtrMap.add(offset, ptr); 314 } 315 316 WTF::Optional<void*> Decoder::cachedPtrForOffset(ptrdiff_t offset) 317 { 318 auto it = m_offsetToPtrMap.find(offset); 319 if (it == m_offsetToPtrMap.end()) 320 return WTF::nullopt; 321 return { it->value }; 322 } 323 324 const void* Decoder::ptrForOffsetFromBase(ptrdiff_t offset) 325 { 326 ASSERT(offset > 0 && static_cast<size_t>(offset) < m_cachedBytecode->size()); 327 return m_cachedBytecode->data() + offset; 328 } 329 330 CompactTDZEnvironmentMap::Handle Decoder::handleForTDZEnvironment(CompactTDZEnvironment* environment) const 331 { 332 auto it = m_environmentToHandleMap.find(environment); 333 RELEASE_ASSERT(it != m_environmentToHandleMap.end()); 334 return it->value; 335 } 336 337 void Decoder::setHandleForTDZEnvironment(CompactTDZEnvironment* environment, const CompactTDZEnvironmentMap::Handle& handle) 338 { 339 auto addResult = m_environmentToHandleMap.add(environment, handle); 340 RELEASE_ASSERT(addResult.isNewEntry); 341 } 342 343 void Decoder::addLeafExecutable(const UnlinkedFunctionExecutable* executable, ptrdiff_t offset) 344 { 345 m_cachedBytecode->leafExecutables().add(executable, offset); 346 } 347 348 template<typename Functor> 349 void Decoder::addFinalizer(const Functor& fn) 350 { 351 m_finalizers.append(fn); 352 } 353 354 RefPtr<SourceProvider> Decoder::provider() const 355 { 356 return m_provider; 357 } 358 359 template<typename T> 360 static std::enable_if_t<std::is_same<T, SourceType<T>>::value> encode(Encoder&, T& dst, const SourceType<T>& src) 361 { 362 dst = src; 363 } 364 365 template<typename T> 366 static std::enable_if_t<!std::is_same<T, SourceType<T>>::value> encode(Encoder& encoder, T& dst, const SourceType<T>& src) 367 { 368 dst.encode(encoder, src); 369 } 370 371 template<typename T, typename... Args> 372 static std::enable_if_t<std::is_same<T, SourceType<T>>::value> decode(Decoder&, const T& src, SourceType<T>& dst, Args...) 373 { 374 dst = src; 375 } 376 377 template<typename T, typename... Args> 378 static std::enable_if_t<!std::is_same<T, SourceType<T>>::value> decode(Decoder& decoder, const T& src, SourceType<T>& dst, Args... args) 379 { 380 src.decode(decoder, dst, args...); 381 } 382 383 template<typename T> 384 static std::enable_if_t<std::is_same<T, SourceType<T>>::value, T> decode(Decoder&, T src) 385 { 386 return src; 387 } 388 389 template<typename T> 390 static std::enable_if_t<!std::is_same<T, SourceType<T>>::value, SourceType<T>>&& decode(Decoder& decoder, const T& src) 391 { 392 return src.decode(decoder); 393 } 394 395 template<typename Source> 396 class CachedObject { 397 WTF_MAKE_NONCOPYABLE(CachedObject<Source>); 398 399 public: 400 using SourceType_ = Source; 401 402 CachedObject() = default; 403 404 inline void* operator new(size_t, void* where) { return where; } 405 void* operator new[](size_t, void* where) { return where; } 406 407 // Copied from WTF_FORBID_HEAP_ALLOCATION, since we only want to allow placement new 408 void* operator new(size_t) = delete; 409 void operator delete(void*) = delete; 410 void* operator new[](size_t size) = delete; 411 void operator delete[](void*) = delete; 412 void* operator new(size_t, NotNullTag, void* location) = delete; 413 }; 414 415 template<typename Source> 416 class VariableLengthObject : public CachedObject<Source>, VariableLengthObjectBase { 417 template<typename, typename> 418 friend class CachedPtr; 419 friend struct CachedPtrOffsets; 420 421 public: 422 VariableLengthObject() 423 : VariableLengthObjectBase(s_invalidOffset) 424 { 425 } 426 427 bool isEmpty() const 428 { 429 return m_offset == s_invalidOffset; 430 } 431 432 protected: 433 const uint8_t* buffer() const 434 { 435 ASSERT(!isEmpty()); 436 return bitwise_cast<const uint8_t*>(this) + m_offset; 437 } 438 439 template<typename T> 440 const T* buffer() const 441 { 442 ASSERT(!(bitwise_cast<uintptr_t>(buffer()) % alignof(T))); 443 return bitwise_cast<const T*>(buffer()); 444 } 445 446 uint8_t* allocate(Encoder& encoder, size_t size) 447 { 448 ptrdiff_t offsetOffset = encoder.offsetOf(&m_offset); 449 auto result = encoder.malloc(size); 450 m_offset = result.offset() - offsetOffset; 451 return result.buffer(); 452 } 453 454 template<typename T> 455 #if CPU(ARM64) && CPU(ADDRESS32) 456 // FIXME: Remove this once it's no longer needed and LLVM doesn't miscompile us: 457 // <rdar://problem/49792205> 458 __attribute__((optnone)) 459 #endif 460 T* allocate(Encoder& encoder, unsigned size = 1) 461 { 462 uint8_t* result = allocate(encoder, sizeof(T) * size); 463 ASSERT(!(bitwise_cast<uintptr_t>(result) % alignof(T))); 464 return new (result) T[size]; 465 } 466 467 private: 468 constexpr static ptrdiff_t s_invalidOffset = std::numeric_limits<ptrdiff_t>::max(); 469 }; 470 471 template<typename T, typename Source = SourceType<T>> 472 class CachedPtr : public VariableLengthObject<Source*> { 473 template<typename, typename, typename> 474 friend class CachedRefPtr; 475 476 friend struct CachedPtrOffsets; 477 478 public: 479 void encode(Encoder& encoder, const Source* src) 480 { 481 if (!src) 482 return; 483 484 if (Optional<ptrdiff_t> offset = encoder.cachedOffsetForPtr(src)) { 485 this->m_offset = *offset - encoder.offsetOf(&this->m_offset); 486 return; 487 } 488 489 T* cachedObject = this->template allocate<T>(encoder); 490 cachedObject->encode(encoder, *src); 491 encoder.cachePtr(src, encoder.offsetOf(cachedObject)); 492 } 493 494 template<typename... Args> 495 Source* decode(Decoder& decoder, bool& isNewAllocation, Args&&... args) const 496 { 497 if (this->isEmpty()) { 498 isNewAllocation = false; 499 return nullptr; 500 } 501 502 ptrdiff_t bufferOffset = decoder.offsetOf(this->buffer()); 503 if (Optional<void*> ptr = decoder.cachedPtrForOffset(bufferOffset)) { 504 isNewAllocation = false; 505 return static_cast<Source*>(*ptr); 506 } 507 508 isNewAllocation = true; 509 Source* ptr = get()->decode(decoder, std::forward<Args>(args)...); 510 decoder.cacheOffset(bufferOffset, ptr); 511 return ptr; 512 } 513 514 template<typename... Args> 515 Source* decode(Decoder& decoder, Args&&... args) const 516 { 517 bool unusedIsNewAllocation; 518 return decode(decoder, unusedIsNewAllocation, std::forward<Args>(args)...); 519 } 520 521 const T* operator->() const { return get(); } 522 523 private: 524 const T* get() const 525 { 526 RELEASE_ASSERT(!this->isEmpty()); 527 return this->template buffer<T>(); 528 } 529 }; 530 531 ptrdiff_t CachedPtrOffsets::offsetOffset() 532 { 533 return OBJECT_OFFSETOF(CachedPtr<void>, m_offset); 534 } 535 536 template<typename T, typename Source = SourceType<T>, typename PtrTraits = RawPtrTraits<Source>> 537 class CachedRefPtr : public CachedObject<RefPtr<Source, PtrTraits>> { 538 public: 539 void encode(Encoder& encoder, const Source* src) 540 { 541 m_ptr.encode(encoder, src); 542 } 543 544 void encode(Encoder& encoder, const RefPtr<Source, PtrTraits> src) 545 { 546 encode(encoder, src.get()); 547 } 548 549 RefPtr<Source, PtrTraits> decode(Decoder& decoder) const 550 { 551 bool isNewAllocation; 552 Source* decodedPtr = m_ptr.decode(decoder, isNewAllocation); 553 if (!decodedPtr) 554 return nullptr; 555 if (isNewAllocation) { 556 decoder.addFinalizer([=] { 557 WTF::DefaultRefDerefTraits<Source>::derefIfNotNull(decodedPtr); 558 }); 559 } 560 auto result = adoptRef<Source, PtrTraits>(decodedPtr); 561 result->ref(); 562 return result; 563 } 564 565 void decode(Decoder& decoder, RefPtr<Source, PtrTraits>& src) const 566 { 567 src = decode(decoder); 568 } 569 570 private: 571 CachedPtr<T, Source> m_ptr; 572 }; 573 574 template<typename T, typename Source = SourceType<T>> 575 class CachedWriteBarrier : public CachedObject<WriteBarrier<Source>> { 576 friend struct CachedWriteBarrierOffsets; 577 578 public: 579 bool isEmpty() const { return m_ptr.isEmpty(); } 580 581 void encode(Encoder& encoder, const WriteBarrier<Source> src) 582 { 583 m_ptr.encode(encoder, src.get()); 584 } 585 586 void decode(Decoder& decoder, WriteBarrier<Source>& src, const JSCell* owner) const 587 { 588 Source* decodedPtr = m_ptr.decode(decoder); 589 if (decodedPtr) 590 src.set(decoder.vm(), owner, decodedPtr); 591 } 592 593 private: 594 CachedPtr<T, Source> m_ptr; 595 }; 596 597 ptrdiff_t CachedWriteBarrierOffsets::ptrOffset() 598 { 599 return OBJECT_OFFSETOF(CachedWriteBarrier<void>, m_ptr); 600 } 601 602 template<typename T, size_t InlineCapacity = 0, typename OverflowHandler = CrashOnOverflow, typename Malloc = WTF::VectorMalloc> 603 class CachedVector : public VariableLengthObject<Vector<SourceType<T>, InlineCapacity, OverflowHandler, 16, Malloc>> { 604 public: 605 void encode(Encoder& encoder, const Vector<SourceType<T>, InlineCapacity, OverflowHandler, 16, Malloc>& vector) 606 { 607 m_size = vector.size(); 608 if (!m_size) 609 return; 610 T* buffer = this->template allocate<T>(encoder, m_size); 611 for (unsigned i = 0; i < m_size; ++i) 612 ::JSC::encode(encoder, buffer[i], vector[i]); 613 } 614 615 void encode(Encoder& encoder, const RefCountedArray<SourceType<T>>& vector) 616 { 617 m_size = vector.size(); 618 if (!m_size) 619 return; 620 T* buffer = this->template allocate<T>(encoder, m_size); 621 for (unsigned i = 0; i < m_size; ++i) 622 ::JSC::encode(encoder, buffer[i], vector[i]); 623 } 624 625 template<typename... Args> 626 void decode(Decoder& decoder, Vector<SourceType<T>, InlineCapacity, OverflowHandler, 16, Malloc>& vector, Args... args) const 627 { 628 if (!m_size) 629 return; 630 vector.resizeToFit(m_size); 631 const T* buffer = this->template buffer<T>(); 632 for (unsigned i = 0; i < m_size; ++i) 633 ::JSC::decode(decoder, buffer[i], vector[i], args...); 634 } 635 636 template<typename... Args> 637 void decode(Decoder& decoder, RefCountedArray<SourceType<T>>& vector, Args... args) const 638 { 639 if (!m_size) 640 return; 641 vector = RefCountedArray<SourceType<T>>(m_size); 642 const T* buffer = this->template buffer<T>(); 643 for (unsigned i = 0; i < m_size; ++i) 644 ::JSC::decode(decoder, buffer[i], vector[i], args...); 645 } 646 647 648 private: 649 unsigned m_size; 650 }; 651 652 template<typename First, typename Second> 653 class CachedPair : public CachedObject<std::pair<SourceType<First>, SourceType<Second>>> { 654 public: 655 void encode(Encoder& encoder, const std::pair<SourceType<First>, SourceType<Second>>& pair) 656 { 657 ::JSC::encode(encoder, m_first, pair.first); 658 ::JSC::encode(encoder, m_second, pair.second); 659 } 660 661 void decode(Decoder& decoder, std::pair<SourceType<First>, SourceType<Second>>& pair) const 662 { 663 ::JSC::decode(decoder, m_first, pair.first); 664 ::JSC::decode(decoder, m_second, pair.second); 665 } 666 667 private: 668 First m_first; 669 Second m_second; 670 }; 671 672 template<typename Key, typename Value, typename HashArg = DefaultHash<SourceType<Key>>, typename KeyTraitsArg = HashTraits<SourceType<Key>>, typename MappedTraitsArg = HashTraits<SourceType<Value>>> 673 class CachedHashMap : public VariableLengthObject<HashMap<SourceType<Key>, SourceType<Value>, HashArg, KeyTraitsArg, MappedTraitsArg>> { 674 template<typename K, typename V> 675 using Map = HashMap<K, V, HashArg, KeyTraitsArg, MappedTraitsArg>; 676 677 public: 678 void encode(Encoder& encoder, const Map<SourceType<Key>, SourceType<Value>>& map) 679 { 680 SourceType<decltype(m_entries)> entriesVector(map.size()); 681 unsigned i = 0; 682 for (const auto& it : map) 683 entriesVector[i++] = { it.key, it.value }; 684 m_entries.encode(encoder, entriesVector); 685 } 686 687 void decode(Decoder& decoder, Map<SourceType<Key>, SourceType<Value>>& map) const 688 { 689 SourceType<decltype(m_entries)> decodedEntries; 690 m_entries.decode(decoder, decodedEntries); 691 for (const auto& pair : decodedEntries) 692 map.set(pair.first, pair.second); 693 } 694 695 private: 696 CachedVector<CachedPair<Key, Value>> m_entries; 697 }; 698 699 template<typename T> 700 class CachedUniquedStringImplBase : public VariableLengthObject<T> { 701 public: 702 void encode(Encoder& encoder, const StringImpl& string) 703 { 704 m_isAtomic = string.isAtom(); 705 m_isSymbol = string.isSymbol(); 706 m_isRegistered = false; 707 m_isWellKnownSymbol = false; 708 m_isPrivate = false; 709 RefPtr<StringImpl> impl = const_cast<StringImpl*>(&string); 710 711 if (m_isSymbol) { 712 SymbolImpl* symbol = static_cast<SymbolImpl*>(impl.get()); 713 m_isRegistered = symbol->isRegistered(); 714 m_isPrivate = symbol->isPrivate(); 715 if (!symbol->isNullSymbol()) { 716 // We have special handling for well-known symbols. 717 if (!m_isPrivate) { 718 m_isWellKnownSymbol = true; 719 impl = symbol->substring(strlen("Symbol.")); 720 } 721 } 722 } 723 724 m_is8Bit = impl->is8Bit(); 725 m_length = impl->length(); 726 727 if (!m_length) 728 return; 729 730 unsigned size = m_length; 731 const void* payload; 732 if (m_is8Bit) 733 payload = impl->characters8(); 734 else { 735 payload = impl->characters16(); 736 size *= 2; 737 } 738 739 uint8_t* buffer = this->allocate(encoder, size); 740 memcpy(buffer, payload, size); 741 } 742 743 UniquedStringImpl* decode(Decoder& decoder) const 744 { 745 auto create = [&](const auto* buffer) -> UniquedStringImpl* { 746 if (!m_isSymbol) 747 return AtomStringImpl::add(buffer, m_length).leakRef(); 748 749 SymbolImpl* symbol; 750 VM& vm = decoder.vm(); 751 if (m_isRegistered) { 752 String str(buffer, m_length); 753 if (m_isPrivate) 754 symbol = static_cast<SymbolImpl*>(&vm.privateSymbolRegistry().symbolForKey(str).leakRef()); 755 else 756 symbol = static_cast<SymbolImpl*>(&vm.symbolRegistry().symbolForKey(str).leakRef()); 757 } else if (m_isWellKnownSymbol) 758 symbol = vm.propertyNames->builtinNames().lookUpWellKnownSymbol(buffer, m_length); 759 else 760 symbol = vm.propertyNames->builtinNames().lookUpPrivateName(buffer, m_length); 761 RELEASE_ASSERT(symbol); 762 String str = symbol; 763 StringImpl* impl = str.releaseImpl().get(); 764 ASSERT(impl->isSymbol()); 765 if (m_isWellKnownSymbol) 766 ASSERT(!static_cast<SymbolImpl*>(impl)->isPrivate()); 767 else 768 ASSERT(static_cast<SymbolImpl*>(impl)->isPrivate()); 769 return static_cast<UniquedStringImpl*>(impl); 770 }; 771 772 if (!m_length) { 773 if (m_isSymbol) 774 return &SymbolImpl::createNullSymbol().leakRef(); 775 return AtomStringImpl::add("").leakRef(); 776 } 777 778 if (m_is8Bit) 779 return create(this->template buffer<LChar>()); 780 return create(this->template buffer<UChar>()); 781 } 782 783 private: 784 bool m_is8Bit : 1; 785 bool m_isSymbol : 1; 786 bool m_isWellKnownSymbol : 1; 787 bool m_isAtomic : 1; 788 bool m_isRegistered : 1; 789 bool m_isPrivate : 1; 790 unsigned m_length; 791 }; 792 793 class CachedUniquedStringImpl : public CachedUniquedStringImplBase<UniquedStringImpl> { }; 794 class CachedStringImpl : public CachedUniquedStringImplBase<StringImpl> { }; 795 796 class CachedString : public VariableLengthObject<String> { 797 public: 798 void encode(Encoder& encoder, const String& string) 799 { 800 m_impl.encode(encoder, static_cast<UniquedStringImpl*>(string.impl())); 801 } 802 803 String decode(Decoder& decoder) const 804 { 805 return String(static_cast<RefPtr<StringImpl>>(m_impl.decode(decoder))); 806 } 807 808 void decode(Decoder& decoder, String& dst) const 809 { 810 dst = decode(decoder); 811 } 812 813 private: 814 CachedRefPtr<CachedUniquedStringImpl> m_impl; 815 }; 816 817 class CachedIdentifier : public VariableLengthObject<Identifier> { 818 public: 819 void encode(Encoder& encoder, const Identifier& identifier) 820 { 821 m_string.encode(encoder, identifier.string()); 822 } 823 824 Identifier decode(Decoder& decoder) const 825 { 826 String str = m_string.decode(decoder); 827 if (str.isNull()) 828 return Identifier(); 829 830 return Identifier::fromUid(decoder.vm(), (UniquedStringImpl*)str.impl()); 831 } 832 833 void decode(Decoder& decoder, Identifier& ident) const 834 { 835 ident = decode(decoder); 836 } 837 838 private: 839 CachedString m_string; 840 }; 841 842 template<typename T> 843 class CachedOptional : public VariableLengthObject<Optional<SourceType<T>>> { 844 public: 845 void encode(Encoder& encoder, const Optional<SourceType<T>>& source) 846 { 847 if (!source) 848 return; 849 850 this->template allocate<T>(encoder)->encode(encoder, *source); 851 } 852 853 Optional<SourceType<T>> decode(Decoder& decoder) const 854 { 855 if (this->isEmpty()) 856 return WTF::nullopt; 857 858 return { this->template buffer<T>()->decode(decoder) }; 859 } 860 861 void decode(Decoder& decoder, Optional<SourceType<T>>& dst) const 862 { 863 dst = decode(decoder); 864 } 865 866 void encode(Encoder& encoder, const std::unique_ptr<SourceType<T>>& source) 867 { 868 if (!source) 869 encode(encoder, WTF::nullopt); 870 else 871 encode(encoder, { *source }); 872 } 873 874 SourceType<T>* decodeAsPtr(Decoder& decoder) const 875 { 876 RELEASE_ASSERT(!this->isEmpty()); 877 return this->template buffer<T>()->decode(decoder); 878 } 879 }; 880 881 class CachedSimpleJumpTable : public CachedObject<UnlinkedSimpleJumpTable> { 882 public: 883 void encode(Encoder& encoder, const UnlinkedSimpleJumpTable& jumpTable) 884 { 885 m_min = jumpTable.min; 886 m_branchOffsets.encode(encoder, jumpTable.branchOffsets); 887 } 888 889 void decode(Decoder& decoder, UnlinkedSimpleJumpTable& jumpTable) const 890 { 891 jumpTable.min = m_min; 892 m_branchOffsets.decode(decoder, jumpTable.branchOffsets); 893 } 894 895 private: 896 int32_t m_min; 897 CachedVector<int32_t> m_branchOffsets; 898 }; 899 900 class CachedStringJumpTable : public CachedObject<UnlinkedStringJumpTable> { 901 public: 902 void encode(Encoder& encoder, const UnlinkedStringJumpTable& jumpTable) 903 { 904 m_offsetTable.encode(encoder, jumpTable.offsetTable); 905 } 906 907 void decode(Decoder& decoder, UnlinkedStringJumpTable& jumpTable) const 908 { 909 m_offsetTable.decode(decoder, jumpTable.offsetTable); 910 } 911 912 private: 913 CachedHashMap<CachedRefPtr<CachedStringImpl>, UnlinkedStringJumpTable:: OffsetLocation> m_offsetTable; 914 }; 915 916 class CachedBitVector : public VariableLengthObject<BitVector> { 917 public: 918 void encode(Encoder& encoder, const BitVector& bitVector) 919 { 920 m_numBits = bitVector.size(); 921 if (!m_numBits) 922 return; 923 size_t sizeInBytes = BitVector::byteCount(m_numBits); 924 uint8_t* buffer = this->allocate(encoder, sizeInBytes); 925 memcpy(buffer, bitVector.bits(), sizeInBytes); 926 } 927 928 void decode(Decoder&, BitVector& bitVector) const 929 { 930 if (!m_numBits) 931 return; 932 bitVector.ensureSize(m_numBits); 933 size_t sizeInBytes = BitVector::byteCount(m_numBits); 934 memcpy(bitVector.bits(), this->buffer(), sizeInBytes); 935 } 936 937 private: 938 size_t m_numBits; 939 }; 940 941 template<typename T, typename HashArg = DefaultHash<T>> 942 class CachedHashSet : public CachedObject<HashSet<SourceType<T>, HashArg>> { 943 public: 944 void encode(Encoder& encoder, const HashSet<SourceType<T>, HashArg>& set) 945 { 946 SourceType<decltype(m_entries)> entriesVector(set.size()); 947 unsigned i = 0; 948 for (const auto& item : set) 949 entriesVector[i++] = item; 950 m_entries.encode(encoder, entriesVector); 951 } 952 953 void decode(Decoder& decoder, HashSet<SourceType<T>, HashArg>& set) const 954 { 955 SourceType<decltype(m_entries)> entriesVector; 956 m_entries.decode(decoder, entriesVector); 957 for (const auto& item : entriesVector) 958 set.add(item); 959 } 960 961 private: 962 CachedVector<T> m_entries; 963 }; 964 965 class CachedConstantIdentifierSetEntry : public VariableLengthObject<ConstantIdentifierSetEntry> { 966 public: 967 void encode(Encoder& encoder, const ConstantIdentifierSetEntry& entry) 968 { 969 m_constant = entry.second; 970 m_set.encode(encoder, entry.first); 971 } 972 973 void decode(Decoder& decoder, ConstantIdentifierSetEntry& entry) const 974 { 975 entry.second = m_constant; 976 m_set.decode(decoder, entry.first); 977 } 978 979 private: 980 unsigned m_constant; 981 CachedHashSet<CachedRefPtr<CachedUniquedStringImpl>, IdentifierRepHash> m_set; 982 }; 983 984 class CachedCodeBlockRareData : public CachedObject<UnlinkedCodeBlock::RareData> { 985 public: 986 void encode(Encoder& encoder, const UnlinkedCodeBlock::RareData& rareData) 987 { 988 m_exceptionHandlers.encode(encoder, rareData.m_exceptionHandlers); 989 m_switchJumpTables.encode(encoder, rareData.m_switchJumpTables); 990 m_stringSwitchJumpTables.encode(encoder, rareData.m_stringSwitchJumpTables); 991 m_expressionInfoFatPositions.encode(encoder, rareData.m_expressionInfoFatPositions); 992 m_typeProfilerInfoMap.encode(encoder, rareData.m_typeProfilerInfoMap); 993 m_opProfileControlFlowBytecodeOffsets.encode(encoder, rareData.m_opProfileControlFlowBytecodeOffsets); 994 m_bitVectors.encode(encoder, rareData.m_bitVectors); 995 m_constantIdentifierSets.encode(encoder, rareData.m_constantIdentifierSets); 996 m_needsClassFieldInitializer = rareData.m_needsClassFieldInitializer; 997 } 998 999 UnlinkedCodeBlock::RareData* decode(Decoder& decoder) const 1000 { 1001 UnlinkedCodeBlock::RareData* rareData = new UnlinkedCodeBlock::RareData { }; 1002 m_exceptionHandlers.decode(decoder, rareData->m_exceptionHandlers); 1003 m_switchJumpTables.decode(decoder, rareData->m_switchJumpTables); 1004 m_stringSwitchJumpTables.decode(decoder, rareData->m_stringSwitchJumpTables); 1005 m_expressionInfoFatPositions.decode(decoder, rareData->m_expressionInfoFatPositions); 1006 m_typeProfilerInfoMap.decode(decoder, rareData->m_typeProfilerInfoMap); 1007 m_opProfileControlFlowBytecodeOffsets.decode(decoder, rareData->m_opProfileControlFlowBytecodeOffsets); 1008 m_bitVectors.decode(decoder, rareData->m_bitVectors); 1009 m_constantIdentifierSets.decode(decoder, rareData->m_constantIdentifierSets); 1010 rareData->m_needsClassFieldInitializer = m_needsClassFieldInitializer; 1011 return rareData; 1012 } 1013 1014 private: 1015 CachedVector<UnlinkedHandlerInfo> m_exceptionHandlers; 1016 CachedVector<CachedSimpleJumpTable> m_switchJumpTables; 1017 CachedVector<CachedStringJumpTable> m_stringSwitchJumpTables; 1018 CachedVector<ExpressionRangeInfo::FatPosition> m_expressionInfoFatPositions; 1019 CachedHashMap<unsigned, UnlinkedCodeBlock::RareData::TypeProfilerExpressionRange> m_typeProfilerInfoMap; 1020 CachedVector<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets; 1021 CachedVector<CachedBitVector> m_bitVectors; 1022 CachedVector<CachedConstantIdentifierSetEntry> m_constantIdentifierSets; 1023 unsigned m_needsClassFieldInitializer : 1; 1024 }; 1025 1026 class CachedVariableEnvironmentRareData : public CachedObject<VariableEnvironment::RareData> { 1027 public: 1028 void encode(Encoder& encoder, const VariableEnvironment::RareData& rareData) 1029 { 1030 m_privateNames.encode(encoder, rareData.m_privateNames); 1031 } 1032 1033 void decode(Decoder& decoder, VariableEnvironment::RareData& rareData) const 1034 { 1035 m_privateNames.decode(decoder, rareData.m_privateNames); 1036 } 1037 1038 private: 1039 CachedHashMap<CachedRefPtr<CachedUniquedStringImpl, UniquedStringImpl, WTF::PackedPtrTraits<UniquedStringImpl>>, PrivateNameEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, PrivateNameEntryHashTraits> m_privateNames; 1040 }; 1041 1042 class CachedVariableEnvironment : public CachedObject<VariableEnvironment> { 1043 public: 1044 void encode(Encoder& encoder, const VariableEnvironment& env) 1045 { 1046 m_isEverythingCaptured = env.m_isEverythingCaptured; 1047 m_map.encode(encoder, env.m_map); 1048 m_rareData.encode(encoder, env.m_rareData.get()); 1049 } 1050 1051 void decode(Decoder& decoder, VariableEnvironment& env) const 1052 { 1053 env.m_isEverythingCaptured = m_isEverythingCaptured; 1054 m_map.decode(decoder, env.m_map); 1055 if (!m_rareData.isEmpty()) { 1056 env.m_rareData = WTF::makeUnique<VariableEnvironment::RareData>(); 1057 m_rareData->decode(decoder, *env.m_rareData); 1058 } 1059 } 1060 1061 private: 1062 bool m_isEverythingCaptured; 1063 CachedHashMap<CachedRefPtr<CachedUniquedStringImpl, UniquedStringImpl, WTF::PackedPtrTraits<UniquedStringImpl>>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> m_map; 1064 CachedPtr<CachedVariableEnvironmentRareData> m_rareData; 1065 }; 1066 1067 class CachedCompactTDZEnvironment : public CachedObject<CompactTDZEnvironment> { 1068 public: 1069 void encode(Encoder& encoder, const CompactTDZEnvironment& env) 1070 { 1071 if (WTF::holds_alternative<CompactTDZEnvironment::Compact>(env.m_variables)) 1072 m_variables.encode(encoder, WTF::get<CompactTDZEnvironment::Compact>(env.m_variables)); 1073 else { 1074 CompactTDZEnvironment::Compact compact; 1075 for (auto& key : WTF::get<CompactTDZEnvironment::Inflated>(env.m_variables)) 1076 compact.append(key); 1077 m_variables.encode(encoder, compact); 1078 } 1079 m_hash = env.m_hash; 1080 } 1081 1082 void decode(Decoder& decoder, CompactTDZEnvironment& env) const 1083 { 1084 { 1085 CompactTDZEnvironment::Compact compact; 1086 m_variables.decode(decoder, compact); 1087 CompactTDZEnvironment::sortCompact(compact); 1088 env.m_variables = CompactTDZEnvironment::Variables(WTFMove(compact)); 1089 } 1090 env.m_hash = m_hash; 1091 } 1092 1093 CompactTDZEnvironment* decode(Decoder& decoder) const 1094 { 1095 CompactTDZEnvironment* env = new CompactTDZEnvironment; 1096 decode(decoder, *env); 1097 return env; 1098 } 1099 1100 private: 1101 CachedVector<CachedRefPtr<CachedUniquedStringImpl, UniquedStringImpl, WTF::PackedPtrTraits<UniquedStringImpl>>> m_variables; 1102 unsigned m_hash; 1103 }; 1104 1105 class CachedCompactTDZEnvironmentMapHandle : public CachedObject<CompactTDZEnvironmentMap::Handle> { 1106 public: 1107 void encode(Encoder& encoder, const CompactTDZEnvironmentMap::Handle& handle) 1108 { 1109 m_environment.encode(encoder, handle.m_environment); 1110 } 1111 1112 CompactTDZEnvironmentMap::Handle decode(Decoder& decoder) const 1113 { 1114 bool isNewAllocation; 1115 CompactTDZEnvironment* environment = m_environment.decode(decoder, isNewAllocation); 1116 if (!environment) { 1117 ASSERT(!isNewAllocation); 1118 return CompactTDZEnvironmentMap::Handle(); 1119 } 1120 1121 if (!isNewAllocation) 1122 return decoder.handleForTDZEnvironment(environment); 1123 bool isNewEntry; 1124 CompactTDZEnvironmentMap::Handle handle = decoder.vm().m_compactVariableMap->get(environment, isNewEntry); 1125 if (!isNewEntry) { 1126 decoder.addFinalizer([=] { 1127 delete environment; 1128 }); 1129 } 1130 decoder.setHandleForTDZEnvironment(environment, handle); 1131 return handle; 1132 } 1133 1134 void decode(Decoder& decoder, CompactTDZEnvironmentMap::Handle& handle) const 1135 { 1136 handle = decode(decoder); 1137 } 1138 1139 private: 1140 CachedPtr<CachedCompactTDZEnvironment> m_environment; 1141 }; 1142 1143 template<typename T, typename Source = SourceType<T>> 1144 class CachedArray : public VariableLengthObject<Source*> { 1145 public: 1146 void encode(Encoder& encoder, const Source* array, unsigned size) 1147 { 1148 if (!size) 1149 return; 1150 T* dst = this->template allocate<T>(encoder, size); 1151 for (unsigned i = 0; i < size; ++i) 1152 ::JSC::encode(encoder, dst[i], array[i]); 1153 } 1154 1155 template<typename... Args> 1156 void decode(Decoder& decoder, Source* array, unsigned size, Args... args) const 1157 { 1158 if (!size) 1159 return; 1160 const T* buffer = this->template buffer<T>(); 1161 for (unsigned i = 0; i < size; ++i) 1162 ::JSC::decode(decoder, buffer[i], array[i], args...); 1163 } 1164 }; 1165 1166 class CachedScopedArgumentsTable : public CachedObject<ScopedArgumentsTable> { 1167 public: 1168 void encode(Encoder& encoder, const ScopedArgumentsTable& scopedArgumentsTable) 1169 { 1170 m_length = scopedArgumentsTable.m_length; 1171 m_arguments.encode(encoder, scopedArgumentsTable.m_arguments.get(m_length), m_length); 1172 } 1173 1174 ScopedArgumentsTable* decode(Decoder& decoder) const 1175 { 1176 ScopedArgumentsTable* scopedArgumentsTable = ScopedArgumentsTable::tryCreate(decoder.vm(), m_length); 1177 RELEASE_ASSERT(scopedArgumentsTable); // We crash here. This is unlikely to continue execution if we hit this condition when decoding UnlinkedCodeBlock. 1178 m_arguments.decode(decoder, scopedArgumentsTable->m_arguments.get(m_length), m_length); 1179 return scopedArgumentsTable; 1180 } 1181 1182 private: 1183 uint32_t m_length; 1184 CachedArray<ScopeOffset> m_arguments; 1185 }; 1186 1187 class CachedSymbolTableEntry : public CachedObject<SymbolTableEntry> { 1188 public: 1189 void encode(Encoder&, const SymbolTableEntry& symbolTableEntry) 1190 { 1191 m_bits = symbolTableEntry.m_bits | SymbolTableEntry::SlimFlag; 1192 } 1193 1194 void decode(Decoder&, SymbolTableEntry& symbolTableEntry) const 1195 { 1196 symbolTableEntry.m_bits = m_bits; 1197 } 1198 1199 private: 1200 intptr_t m_bits; 1201 }; 1202 1203 class CachedSymbolTableRareData : public CachedObject<SymbolTable::SymbolTableRareData> { 1204 public: 1205 void encode(Encoder& encoder, const SymbolTable::SymbolTableRareData& rareData) 1206 { 1207 m_privateNames.encode(encoder, rareData.m_privateNames); 1208 } 1209 1210 void decode(Decoder& decoder, SymbolTable::SymbolTableRareData& rareData) const 1211 { 1212 m_privateNames.decode(decoder, rareData.m_privateNames); 1213 } 1214 1215 private: 1216 CachedHashSet<CachedRefPtr<CachedUniquedStringImpl>, IdentifierRepHash> m_privateNames; 1217 }; 1218 1219 class CachedSymbolTable : public CachedObject<SymbolTable> { 1220 public: 1221 void encode(Encoder& encoder, const SymbolTable& symbolTable) 1222 { 1223 m_map.encode(encoder, symbolTable.m_map); 1224 m_maxScopeOffset = symbolTable.m_maxScopeOffset; 1225 m_usesNonStrictEval = symbolTable.m_usesNonStrictEval; 1226 m_nestedLexicalScope = symbolTable.m_nestedLexicalScope; 1227 m_scopeType = symbolTable.m_scopeType; 1228 m_arguments.encode(encoder, symbolTable.m_arguments.get()); 1229 m_rareData.encode(encoder, symbolTable.m_rareData.get()); 1230 } 1231 1232 SymbolTable* decode(Decoder& decoder) const 1233 { 1234 SymbolTable* symbolTable = SymbolTable::create(decoder.vm()); 1235 m_map.decode(decoder, symbolTable->m_map); 1236 symbolTable->m_maxScopeOffset = m_maxScopeOffset; 1237 symbolTable->m_usesNonStrictEval = m_usesNonStrictEval; 1238 symbolTable->m_nestedLexicalScope = m_nestedLexicalScope; 1239 symbolTable->m_scopeType = m_scopeType; 1240 ScopedArgumentsTable* scopedArgumentsTable = m_arguments.decode(decoder); 1241 if (scopedArgumentsTable) 1242 symbolTable->m_arguments.set(decoder.vm(), symbolTable, scopedArgumentsTable); 1243 if (!m_rareData.isEmpty()) { 1244 symbolTable->m_rareData = WTF::makeUnique<SymbolTable::SymbolTableRareData>(); 1245 m_rareData->decode(decoder, *symbolTable->m_rareData); 1246 } 1247 1248 return symbolTable; 1249 } 1250 1251 private: 1252 CachedHashMap<CachedRefPtr<CachedUniquedStringImpl>, CachedSymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, SymbolTableIndexHashTraits> m_map; 1253 ScopeOffset m_maxScopeOffset; 1254 unsigned m_usesNonStrictEval : 1; 1255 unsigned m_nestedLexicalScope : 1; 1256 unsigned m_scopeType : 3; 1257 CachedPtr<CachedScopedArgumentsTable> m_arguments; 1258 CachedPtr<CachedSymbolTableRareData> m_rareData; 1259 }; 1260 1261 class CachedJSValue; 1262 class CachedImmutableButterfly : public CachedObject<JSImmutableButterfly> { 1263 public: 1264 CachedImmutableButterfly() 1265 : m_cachedDoubles() 1266 { 1267 } 1268 1269 void encode(Encoder& encoder, JSImmutableButterfly& immutableButterfly) 1270 { 1271 m_length = immutableButterfly.length(); 1272 m_indexingType = immutableButterfly.indexingTypeAndMisc(); 1273 if (hasDouble(m_indexingType)) 1274 m_cachedDoubles.encode(encoder, immutableButterfly.toButterfly()->contiguousDouble().data(), m_length); 1275 else 1276 m_cachedValues.encode(encoder, immutableButterfly.toButterfly()->contiguous().data(), m_length); 1277 } 1278 1279 JSImmutableButterfly* decode(Decoder& decoder) const 1280 { 1281 JSImmutableButterfly* immutableButterfly = JSImmutableButterfly::create(decoder.vm(), m_indexingType, m_length); 1282 if (hasDouble(m_indexingType)) 1283 m_cachedDoubles.decode(decoder, immutableButterfly->toButterfly()->contiguousDouble().data(), m_length, immutableButterfly); 1284 else 1285 m_cachedValues.decode(decoder, immutableButterfly->toButterfly()->contiguous().data(), m_length, immutableButterfly); 1286 return immutableButterfly; 1287 } 1288 1289 private: 1290 IndexingType m_indexingType; 1291 unsigned m_length; 1292 union { 1293 CachedArray<double> m_cachedDoubles; 1294 CachedArray<CachedJSValue, WriteBarrier<Unknown>> m_cachedValues; 1295 }; 1296 }; 1297 1298 class CachedRegExp : public CachedObject<RegExp> { 1299 public: 1300 void encode(Encoder& encoder, const RegExp& regExp) 1301 { 1302 m_patternString.encode(encoder, regExp.m_patternString); 1303 m_flags = regExp.m_flags; 1304 } 1305 1306 RegExp* decode(Decoder& decoder) const 1307 { 1308 String pattern { m_patternString.decode(decoder) }; 1309 return RegExp::create(decoder.vm(), pattern, m_flags); 1310 } 1311 1312 private: 1313 CachedString m_patternString; 1314 OptionSet<Yarr::Flags> m_flags; 1315 }; 1316 1317 class CachedTemplateObjectDescriptor : public CachedObject<TemplateObjectDescriptor> { 1318 public: 1319 void encode(Encoder& encoder, const JSTemplateObjectDescriptor& descriptor) 1320 { 1321 m_rawStrings.encode(encoder, descriptor.descriptor().rawStrings()); 1322 m_cookedStrings.encode(encoder, descriptor.descriptor().cookedStrings()); 1323 m_endOffset = descriptor.endOffset(); 1324 } 1325 1326 JSTemplateObjectDescriptor* decode(Decoder& decoder) const 1327 { 1328 TemplateObjectDescriptor::StringVector decodedRawStrings; 1329 TemplateObjectDescriptor::OptionalStringVector decodedCookedStrings; 1330 m_rawStrings.decode(decoder, decodedRawStrings); 1331 m_cookedStrings.decode(decoder, decodedCookedStrings); 1332 return JSTemplateObjectDescriptor::create(decoder.vm(), TemplateObjectDescriptor::create(WTFMove(decodedRawStrings), WTFMove(decodedCookedStrings)), m_endOffset); 1333 } 1334 1335 private: 1336 CachedVector<CachedString, 4> m_rawStrings; 1337 CachedVector<CachedOptional<CachedString>, 4> m_cookedStrings; 1338 int m_endOffset; 1339 }; 1340 1341 class CachedBigInt : public VariableLengthObject<JSBigInt> { 1342 public: 1343 void encode(Encoder& encoder, JSBigInt& bigInt) 1344 { 1345 m_length = bigInt.length(); 1346 m_sign = bigInt.sign(); 1347 1348 if (!m_length) 1349 return; 1350 1351 unsigned size = sizeof(JSBigInt::Digit) * m_length; 1352 uint8_t* buffer = this->allocate(encoder, size); 1353 memcpy(buffer, bigInt.dataStorage(), size); 1354 } 1355 1356 JSBigInt* decode(Decoder& decoder) const 1357 { 1358 JSBigInt* bigInt = JSBigInt::tryCreateWithLength(decoder.vm(), m_length); 1359 RELEASE_ASSERT(bigInt); 1360 bigInt->setSign(m_sign); 1361 if (m_length) 1362 memcpy(bigInt->dataStorage(), this->buffer(), sizeof(JSBigInt::Digit) * m_length); 1363 return bigInt; 1364 } 1365 1366 private: 1367 unsigned m_length; 1368 bool m_sign; 1369 }; 1370 1371 class CachedJSValue : public VariableLengthObject<WriteBarrier<Unknown>> { 1372 public: 1373 void encode(Encoder& encoder, const WriteBarrier<Unknown> value) 1374 { 1375 JSValue v = value.get(); 1376 1377 if (!v.isCell() || v.isEmpty()) { 1378 m_type = EncodedType::JSValue; 1379 *this->allocate<EncodedJSValue>(encoder) = JSValue::encode(v); 1380 return; 1381 } 1382 1383 JSCell* cell = v.asCell(); 1384 VM& vm = encoder.vm(); 1385 1386 if (auto* symbolTable = jsDynamicCast<SymbolTable*>(vm, cell)) { 1387 m_type = EncodedType::SymbolTable; 1388 this->allocate<CachedSymbolTable>(encoder)->encode(encoder, *symbolTable); 1389 return; 1390 } 1391 1392 if (auto* string = jsDynamicCast<JSString*>(vm, cell)) { 1393 m_type = EncodedType::String; 1394 StringImpl* impl = string->tryGetValue().impl(); 1395 this->allocate<CachedUniquedStringImpl>(encoder)->encode(encoder, *impl); 1396 return; 1397 } 1398 1399 if (auto* immutableButterfly = jsDynamicCast<JSImmutableButterfly*>(vm, cell)) { 1400 m_type = EncodedType::ImmutableButterfly; 1401 this->allocate<CachedImmutableButterfly>(encoder)->encode(encoder, *immutableButterfly); 1402 return; 1403 } 1404 1405 if (auto* regexp = jsDynamicCast<RegExp*>(vm, cell)) { 1406 m_type = EncodedType::RegExp; 1407 this->allocate<CachedRegExp>(encoder)->encode(encoder, *regexp); 1408 return; 1409 } 1410 1411 if (auto* templateObjectDescriptor = jsDynamicCast<JSTemplateObjectDescriptor*>(vm, cell)) { 1412 m_type = EncodedType::TemplateObjectDescriptor; 1413 this->allocate<CachedTemplateObjectDescriptor>(encoder)->encode(encoder, *templateObjectDescriptor); 1414 return; 1415 } 1416 1417 if (auto* bigInt = jsDynamicCast<JSBigInt*>(vm, cell)) { 1418 m_type = EncodedType::BigInt; 1419 this->allocate<CachedBigInt>(encoder)->encode(encoder, *bigInt); 1420 return; 1421 } 1422 1423 RELEASE_ASSERT_NOT_REACHED(); 1424 } 1425 1426 void decode(Decoder& decoder, WriteBarrier<Unknown>& value, const JSCell* owner) const 1427 { 1428 JSValue v; 1429 switch (m_type) { 1430 case EncodedType::JSValue: 1431 v = JSValue::decode(*this->buffer<EncodedJSValue>()); 1432 break; 1433 case EncodedType::SymbolTable: 1434 v = this->buffer<CachedSymbolTable>()->decode(decoder); 1435 break; 1436 case EncodedType::String: { 1437 StringImpl* impl = this->buffer<CachedUniquedStringImpl>()->decode(decoder); 1438 v = jsString(decoder.vm(), adoptRef(*impl)); 1439 break; 1440 } 1441 case EncodedType::ImmutableButterfly: 1442 v = this->buffer<CachedImmutableButterfly>()->decode(decoder); 1443 break; 1444 case EncodedType::RegExp: 1445 v = this->buffer<CachedRegExp>()->decode(decoder); 1446 break; 1447 case EncodedType::TemplateObjectDescriptor: 1448 v = this->buffer<CachedTemplateObjectDescriptor>()->decode(decoder); 1449 break; 1450 case EncodedType::BigInt: 1451 v = this->buffer<CachedBigInt>()->decode(decoder); 1452 break; 1453 default: 1454 RELEASE_ASSERT_NOT_REACHED(); 1455 } 1456 value.set(decoder.vm(), owner, v); 1457 } 1458 1459 private: 1460 enum class EncodedType : uint8_t { 1461 JSValue, 1462 SymbolTable, 1463 String, 1464 ImmutableButterfly, 1465 RegExp, 1466 TemplateObjectDescriptor, 1467 BigInt, 1468 }; 1469 1470 EncodedType m_type; 1471 }; 1472 1473 class CachedInstructionStream : public CachedObject<InstructionStream> { 1474 public: 1475 void encode(Encoder& encoder, const InstructionStream& stream) 1476 { 1477 m_instructions.encode(encoder, stream.m_instructions); 1478 } 1479 1480 InstructionStream* decode(Decoder& decoder) const 1481 { 1482 Vector<uint8_t, 0, UnsafeVectorOverflow, 16, InstructionStreamMalloc> instructionsVector; 1483 m_instructions.decode(decoder, instructionsVector); 1484 return new InstructionStream(WTFMove(instructionsVector)); 1485 } 1486 1487 private: 1488 CachedVector<uint8_t, 0, UnsafeVectorOverflow, InstructionStreamMalloc> m_instructions; 1489 }; 1490 1491 class CachedMetadataTable : public CachedObject<UnlinkedMetadataTable> { 1492 public: 1493 void encode(Encoder&, const UnlinkedMetadataTable& metadataTable) 1494 { 1495 ASSERT(metadataTable.m_isFinalized); 1496 m_hasMetadata = metadataTable.m_hasMetadata; 1497 if (!m_hasMetadata) 1498 return; 1499 m_is32Bit = metadataTable.m_is32Bit; 1500 if (m_is32Bit) { 1501 for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) 1502 m_metadata[i] = metadataTable.offsetTable32()[i]; 1503 } else { 1504 for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) 1505 m_metadata[i] = metadataTable.offsetTable16()[i]; 1506 } 1507 } 1508 1509 Ref<UnlinkedMetadataTable> decode(Decoder&) const 1510 { 1511 if (!m_hasMetadata) 1512 return UnlinkedMetadataTable::empty(); 1513 1514 Ref<UnlinkedMetadataTable> metadataTable = UnlinkedMetadataTable::create(m_is32Bit); 1515 metadataTable->m_isFinalized = true; 1516 metadataTable->m_isLinked = false; 1517 metadataTable->m_hasMetadata = m_hasMetadata; 1518 if (m_is32Bit) { 1519 for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) 1520 metadataTable->offsetTable32()[i] = m_metadata[i]; 1521 } else { 1522 for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) 1523 metadataTable->offsetTable16()[i] = m_metadata[i]; 1524 } 1525 return metadataTable; 1526 } 1527 1528 private: 1529 bool m_hasMetadata; 1530 bool m_is32Bit; 1531 std::array<unsigned, UnlinkedMetadataTable::s_offsetTableEntries> m_metadata; 1532 }; 1533 1534 class CachedSourceOrigin : public CachedObject<SourceOrigin> { 1535 public: 1536 void encode(Encoder& encoder, const SourceOrigin& sourceOrigin) 1537 { 1538 m_string.encode(encoder, sourceOrigin.url().string()); 1539 } 1540 1541 SourceOrigin decode(Decoder& decoder) const 1542 { 1543 return SourceOrigin { URL({ }, m_string.decode(decoder)) }; 1544 } 1545 1546 private: 1547 CachedString m_string; 1548 }; 1549 1550 class CachedTextPosition : public CachedObject<TextPosition> { 1551 public: 1552 void encode(Encoder&, TextPosition textPosition) 1553 { 1554 m_line = textPosition.m_line.zeroBasedInt(); 1555 m_column = textPosition.m_column.zeroBasedInt(); 1556 } 1557 1558 TextPosition decode(Decoder&) const 1559 { 1560 return TextPosition { OrdinalNumber::fromZeroBasedInt(m_line), OrdinalNumber::fromZeroBasedInt(m_column) }; 1561 } 1562 1563 private: 1564 int m_line; 1565 int m_column; 1566 }; 1567 1568 template <typename Source, typename CachedType> 1569 class CachedSourceProviderShape : public CachedObject<Source> { 1570 public: 1571 void encode(Encoder& encoder, const SourceProvider& sourceProvider) 1572 { 1573 m_sourceOrigin.encode(encoder, sourceProvider.sourceOrigin()); 1574 m_sourceURL.encode(encoder, sourceProvider.sourceURL()); 1575 m_sourceURLDirective.encode(encoder, sourceProvider.sourceURLDirective()); 1576 m_sourceMappingURLDirective.encode(encoder, sourceProvider.sourceMappingURLDirective()); 1577 m_startPosition.encode(encoder, sourceProvider.startPosition()); 1578 } 1579 1580 void decode(Decoder& decoder, SourceProvider& sourceProvider) const 1581 { 1582 sourceProvider.setSourceURLDirective(m_sourceURLDirective.decode(decoder)); 1583 sourceProvider.setSourceMappingURLDirective(m_sourceMappingURLDirective.decode(decoder)); 1584 } 1585 1586 protected: 1587 CachedSourceOrigin m_sourceOrigin; 1588 CachedString m_sourceURL; 1589 CachedString m_sourceURLDirective; 1590 CachedString m_sourceMappingURLDirective; 1591 CachedTextPosition m_startPosition; 1592 }; 1593 1594 class CachedStringSourceProvider : public CachedSourceProviderShape<StringSourceProvider, CachedStringSourceProvider> { 1595 using Base = CachedSourceProviderShape<StringSourceProvider, CachedStringSourceProvider>; 1596 1597 public: 1598 void encode(Encoder& encoder, const StringSourceProvider& sourceProvider) 1599 { 1600 Base::encode(encoder, sourceProvider); 1601 m_source.encode(encoder, sourceProvider.source().toString()); 1602 } 1603 1604 StringSourceProvider* decode(Decoder& decoder, SourceProviderSourceType sourceType) const 1605 { 1606 String decodedSource = m_source.decode(decoder); 1607 SourceOrigin decodedSourceOrigin = m_sourceOrigin.decode(decoder); 1608 String decodedSourceURL = m_sourceURL.decode(decoder); 1609 TextPosition decodedStartPosition = m_startPosition.decode(decoder); 1610 1611 Ref<StringSourceProvider> sourceProvider = StringSourceProvider::create(decodedSource, decodedSourceOrigin, decodedSourceURL, decodedStartPosition, sourceType); 1612 Base::decode(decoder, sourceProvider.get()); 1613 return &sourceProvider.leakRef(); 1614 } 1615 1616 private: 1617 CachedString m_source; 1618 }; 1619 1620 #if ENABLE(WEBASSEMBLY) 1621 class CachedWebAssemblySourceProvider : public CachedSourceProviderShape<WebAssemblySourceProvider, CachedWebAssemblySourceProvider> { 1622 using Base = CachedSourceProviderShape<WebAssemblySourceProvider, CachedWebAssemblySourceProvider>; 1623 1624 public: 1625 void encode(Encoder& encoder, const WebAssemblySourceProvider& sourceProvider) 1626 { 1627 Base::encode(encoder, sourceProvider); 1628 m_data.encode(encoder, sourceProvider.data()); 1629 } 1630 1631 WebAssemblySourceProvider* decode(Decoder& decoder) const 1632 { 1633 Vector<uint8_t> decodedData; 1634 SourceOrigin decodedSourceOrigin = m_sourceOrigin.decode(decoder); 1635 String decodedSourceURL = m_sourceURL.decode(decoder); 1636 1637 m_data.decode(decoder, decodedData); 1638 1639 Ref<WebAssemblySourceProvider> sourceProvider = WebAssemblySourceProvider::create(WTFMove(decodedData), decodedSourceOrigin, decodedSourceURL); 1640 Base::decode(decoder, sourceProvider.get()); 1641 1642 return &sourceProvider.leakRef(); 1643 } 1644 1645 private: 1646 CachedVector<uint8_t> m_data; 1647 }; 1648 #endif 1649 1650 class CachedSourceProvider : public VariableLengthObject<SourceProvider> { 1651 public: 1652 void encode(Encoder& encoder, const SourceProvider& sourceProvider) 1653 { 1654 m_sourceType = sourceProvider.sourceType(); 1655 switch (m_sourceType) { 1656 case SourceProviderSourceType::Program: 1657 case SourceProviderSourceType::Module: 1658 this->allocate<CachedStringSourceProvider>(encoder)->encode(encoder, reinterpret_cast<const StringSourceProvider&>(sourceProvider)); 1659 break; 1660 #if ENABLE(WEBASSEMBLY) 1661 case SourceProviderSourceType::WebAssembly: 1662 this->allocate<CachedWebAssemblySourceProvider>(encoder)->encode(encoder, reinterpret_cast<const WebAssemblySourceProvider&>(sourceProvider)); 1663 break; 1664 #endif 1665 default: 1666 RELEASE_ASSERT_NOT_REACHED(); 1667 } 1668 } 1669 1670 SourceProvider* decode(Decoder& decoder) const 1671 { 1672 switch (m_sourceType) { 1673 case SourceProviderSourceType::Program: 1674 case SourceProviderSourceType::Module: 1675 return this->buffer<CachedStringSourceProvider>()->decode(decoder, m_sourceType); 1676 #if ENABLE(WEBASSEMBLY) 1677 case SourceProviderSourceType::WebAssembly: 1678 return this->buffer<CachedWebAssemblySourceProvider>()->decode(decoder); 1679 #endif 1680 default: 1681 RELEASE_ASSERT_NOT_REACHED(); 1682 } 1683 } 1684 1685 private: 1686 SourceProviderSourceType m_sourceType; 1687 }; 1688 1689 template<typename Source> 1690 class CachedUnlinkedSourceCodeShape : public CachedObject<Source> { 1691 public: 1692 void encode(Encoder& encoder, const UnlinkedSourceCode& sourceCode) 1693 { 1694 m_provider.encode(encoder, sourceCode.m_provider); 1695 m_startOffset = sourceCode.startOffset(); 1696 m_endOffset = sourceCode.endOffset(); 1697 } 1698 1699 void decode(Decoder& decoder, UnlinkedSourceCode& sourceCode) const 1700 { 1701 sourceCode.m_provider = m_provider.decode(decoder); 1702 sourceCode.m_startOffset = m_startOffset; 1703 sourceCode.m_endOffset = m_endOffset; 1704 } 1705 1706 private: 1707 CachedRefPtr<CachedSourceProvider> m_provider; 1708 int m_startOffset; 1709 int m_endOffset; 1710 }; 1711 1712 1713 class CachedUnlinkedSourceCode : public CachedUnlinkedSourceCodeShape<UnlinkedSourceCode> { }; 1714 1715 class CachedSourceCode : public CachedUnlinkedSourceCodeShape<SourceCode> { 1716 using Base = CachedUnlinkedSourceCodeShape<SourceCode>; 1717 1718 public: 1719 void encode(Encoder& encoder, const SourceCode& sourceCode) 1720 { 1721 Base::encode(encoder, sourceCode); 1722 m_firstLine = sourceCode.firstLine().zeroBasedInt(); 1723 m_startColumn = sourceCode.startColumn().zeroBasedInt(); 1724 } 1725 1726 void decode(Decoder& decoder, SourceCode& sourceCode) const 1727 { 1728 Base::decode(decoder, sourceCode); 1729 sourceCode.m_firstLine = OrdinalNumber::fromZeroBasedInt(m_firstLine); 1730 sourceCode.m_startColumn = OrdinalNumber::fromZeroBasedInt(m_startColumn); 1731 } 1732 1733 private: 1734 int m_firstLine; 1735 int m_startColumn; 1736 }; 1737 1738 class CachedSourceCodeWithoutProvider : public CachedObject<SourceCode> { 1739 public: 1740 void encode(Encoder&, const SourceCode& sourceCode) 1741 { 1742 m_hasProvider = !!sourceCode.provider(); 1743 m_startOffset = sourceCode.startOffset(); 1744 m_endOffset = sourceCode.endOffset(); 1745 m_firstLine = sourceCode.firstLine().zeroBasedInt(); 1746 m_startColumn = sourceCode.startColumn().zeroBasedInt(); 1747 } 1748 1749 void decode(Decoder& decoder, SourceCode& sourceCode) const 1750 { 1751 if (m_hasProvider) 1752 sourceCode.m_provider = decoder.provider(); 1753 sourceCode.m_startOffset = m_startOffset; 1754 sourceCode.m_endOffset = m_endOffset; 1755 sourceCode.m_firstLine = OrdinalNumber::fromZeroBasedInt(m_firstLine); 1756 sourceCode.m_startColumn = OrdinalNumber::fromZeroBasedInt(m_startColumn); 1757 } 1758 1759 private: 1760 bool m_hasProvider; 1761 int m_startOffset; 1762 int m_endOffset; 1763 int m_firstLine; 1764 int m_startColumn; 1765 }; 1766 1767 class CachedTDZEnvironmentLink : public CachedObject<TDZEnvironmentLink> { 1768 public: 1769 void encode(Encoder& encoder, const TDZEnvironmentLink& environment) 1770 { 1771 m_handle.encode(encoder, environment.m_handle); 1772 m_parent.encode(encoder, environment.m_parent); 1773 } 1774 1775 TDZEnvironmentLink* decode(Decoder& decoder) const 1776 { 1777 CompactTDZEnvironmentMap::Handle handle = m_handle.decode(decoder); 1778 RefPtr<TDZEnvironmentLink> parent = m_parent.decode(decoder); 1779 return new TDZEnvironmentLink(WTFMove(handle), WTFMove(parent)); 1780 } 1781 1782 private: 1783 CachedCompactTDZEnvironmentMapHandle m_handle; 1784 CachedRefPtr<CachedTDZEnvironmentLink> m_parent; 1785 }; 1786 1787 class CachedFunctionExecutableRareData : public CachedObject<UnlinkedFunctionExecutable::RareData> { 1788 public: 1789 void encode(Encoder& encoder, const UnlinkedFunctionExecutable::RareData& rareData) 1790 { 1791 m_classSource.encode(encoder, rareData.m_classSource); 1792 m_parentScopeTDZVariables.encode(encoder, rareData.m_parentScopeTDZVariables); 1793 } 1794 1795 UnlinkedFunctionExecutable::RareData* decode(Decoder& decoder) const 1796 { 1797 UnlinkedFunctionExecutable::RareData* rareData = new UnlinkedFunctionExecutable::RareData { }; 1798 m_classSource.decode(decoder, rareData->m_classSource); 1799 m_parentScopeTDZVariables.decode(decoder, rareData->m_parentScopeTDZVariables); 1800 return rareData; 1801 } 1802 1803 private: 1804 CachedSourceCodeWithoutProvider m_classSource; 1805 CachedRefPtr<CachedTDZEnvironmentLink> m_parentScopeTDZVariables; 1806 }; 1807 1808 class CachedFunctionExecutable : public CachedObject<UnlinkedFunctionExecutable> { 1809 friend struct CachedFunctionExecutableOffsets; 1810 1811 public: 1812 void encode(Encoder&, const UnlinkedFunctionExecutable&); 1813 UnlinkedFunctionExecutable* decode(Decoder&) const; 1814 1815 unsigned firstLineOffset() const { return m_firstLineOffset; } 1816 unsigned lineCount() const { return m_lineCount; } 1817 unsigned unlinkedFunctionNameStart() const { return m_unlinkedFunctionNameStart; } 1818 unsigned unlinkedBodyStartColumn() const { return m_unlinkedBodyStartColumn; } 1819 unsigned unlinkedBodyEndColumn() const { return m_unlinkedBodyEndColumn; } 1820 unsigned startOffset() const { return m_startOffset; } 1821 unsigned sourceLength() const { return m_sourceLength; } 1822 unsigned parametersStartOffset() const { return m_parametersStartOffset; } 1823 unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; } 1824 unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; } 1825 unsigned parameterCount() const { return m_parameterCount; } 1826 1827 CodeFeatures features() const { return m_mutableMetadata.m_features; } 1828 SourceParseMode sourceParseMode() const { return m_sourceParseMode; } 1829 1830 unsigned isInStrictContext() const { return m_isInStrictContext; } 1831 unsigned hasCapturedVariables() const { return m_mutableMetadata.m_hasCapturedVariables; } 1832 unsigned isBuiltinFunction() const { return m_isBuiltinFunction; } 1833 unsigned isBuiltinDefaultClassConstructor() const { return m_isBuiltinDefaultClassConstructor; } 1834 unsigned constructAbility() const { return m_constructAbility; } 1835 unsigned constructorKind() const { return m_constructorKind; } 1836 unsigned functionMode() const { return m_functionMode; } 1837 unsigned scriptMode() const { return m_scriptMode; } 1838 unsigned superBinding() const { return m_superBinding; } 1839 unsigned derivedContextType() const { return m_derivedContextType; } 1840 unsigned needsClassFieldInitializer() const { return m_needsClassFieldInitializer; } 1841 1842 Identifier name(Decoder& decoder) const { return m_name.decode(decoder); } 1843 Identifier ecmaName(Decoder& decoder) const { return m_ecmaName.decode(decoder); } 1844 1845 UnlinkedFunctionExecutable::RareData* rareData(Decoder& decoder) const { return m_rareData.decode(decoder); } 1846 1847 const CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock>& unlinkedCodeBlockForCall() const { return m_unlinkedCodeBlockForCall; } 1848 const CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock>& unlinkedCodeBlockForConstruct() const { return m_unlinkedCodeBlockForConstruct; } 1849 1850 private: 1851 CachedFunctionExecutableMetadata m_mutableMetadata; 1852 1853 unsigned m_firstLineOffset : 31; 1854 unsigned m_isInStrictContext : 1; 1855 unsigned m_lineCount : 31; 1856 unsigned m_isBuiltinFunction : 1; 1857 unsigned m_unlinkedFunctionNameStart : 31; 1858 unsigned m_isBuiltinDefaultClassConstructor : 1; 1859 unsigned m_unlinkedBodyStartColumn : 31; 1860 unsigned m_constructAbility: 1; 1861 unsigned m_unlinkedBodyEndColumn : 31; 1862 unsigned m_startOffset : 31; 1863 unsigned m_scriptMode: 1; // JSParserScriptMode 1864 unsigned m_sourceLength : 31; 1865 unsigned m_superBinding : 1; 1866 unsigned m_parametersStartOffset : 31; 1867 unsigned m_typeProfilingStartOffset; 1868 unsigned m_typeProfilingEndOffset; 1869 unsigned m_parameterCount; 1870 SourceParseMode m_sourceParseMode; 1871 unsigned m_constructorKind : 2; 1872 unsigned m_functionMode : 2; // FunctionMode 1873 unsigned m_derivedContextType: 2; 1874 unsigned m_needsClassFieldInitializer : 1; 1875 1876 CachedPtr<CachedFunctionExecutableRareData> m_rareData; 1877 1878 CachedIdentifier m_name; 1879 CachedIdentifier m_ecmaName; 1880 1881 CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall; 1882 CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct; 1883 }; 1884 1885 ptrdiff_t CachedFunctionExecutableOffsets::codeBlockForCallOffset() 1886 { 1887 return OBJECT_OFFSETOF(CachedFunctionExecutable, m_unlinkedCodeBlockForCall); 1888 } 1889 1890 ptrdiff_t CachedFunctionExecutableOffsets::codeBlockForConstructOffset() 1891 { 1892 return OBJECT_OFFSETOF(CachedFunctionExecutable, m_unlinkedCodeBlockForConstruct); 1893 } 1894 1895 ptrdiff_t CachedFunctionExecutableOffsets::metadataOffset() 1896 { 1897 return OBJECT_OFFSETOF(CachedFunctionExecutable, m_mutableMetadata); 1898 } 1899 1900 template<typename CodeBlockType> 1901 class CachedCodeBlock : public CachedObject<CodeBlockType> { 1902 public: 1903 void encode(Encoder&, const UnlinkedCodeBlock&); 1904 void decode(Decoder&, UnlinkedCodeBlock&) const; 1905 1906 InstructionStream* instructions(Decoder& decoder) const { return m_instructions.decode(decoder); } 1907 1908 VirtualRegister thisRegister() const { return m_thisRegister; } 1909 VirtualRegister scopeRegister() const { return m_scopeRegister; } 1910 1911 RefPtr<StringImpl> sourceURLDirective(Decoder& decoder) const { return m_sourceURLDirective.decode(decoder); } 1912 RefPtr<StringImpl> sourceMappingURLDirective(Decoder& decoder) const { return m_sourceMappingURLDirective.decode(decoder); } 1913 1914 Ref<UnlinkedMetadataTable> metadata(Decoder& decoder) const { return m_metadata.decode(decoder); } 1915 1916 unsigned usesEval() const { return m_usesEval; } 1917 unsigned isConstructor() const { return m_isConstructor; } 1918 unsigned hasCapturedVariables() const { return m_hasCapturedVariables; } 1919 unsigned isBuiltinFunction() const { return m_isBuiltinFunction; } 1920 unsigned superBinding() const { return m_superBinding; } 1921 unsigned scriptMode() const { return m_scriptMode; } 1922 unsigned isArrowFunctionContext() const { return m_isArrowFunctionContext; } 1923 unsigned isClassContext() const { return m_isClassContext; } 1924 unsigned constructorKind() const { return m_constructorKind; } 1925 unsigned derivedContextType() const { return m_derivedContextType; } 1926 unsigned needsClassFieldInitializer() const { return m_needsClassFieldInitializer; } 1927 unsigned evalContextType() const { return m_evalContextType; } 1928 unsigned hasTailCalls() const { return m_hasTailCalls; } 1929 unsigned hasCheckpoints() const { return m_hasCheckpoints; } 1930 unsigned lineCount() const { return m_lineCount; } 1931 unsigned endColumn() const { return m_endColumn; } 1932 1933 int numVars() const { return m_numVars; } 1934 int numCalleeLocals() const { return m_numCalleeLocals; } 1935 int numParameters() const { return m_numParameters; } 1936 1937 CodeFeatures features() const { return m_features; } 1938 SourceParseMode parseMode() const { return m_parseMode; } 1939 OptionSet<CodeGenerationMode> codeGenerationMode() const { return m_codeGenerationMode; } 1940 unsigned codeType() const { return m_codeType; } 1941 1942 UnlinkedCodeBlock::RareData* rareData(Decoder& decoder) const { return m_rareData.decode(decoder); } 1943 1944 private: 1945 VirtualRegister m_thisRegister; 1946 VirtualRegister m_scopeRegister; 1947 1948 unsigned m_usesEval : 1; 1949 unsigned m_isConstructor : 1; 1950 unsigned m_hasCapturedVariables : 1; 1951 unsigned m_isBuiltinFunction : 1; 1952 unsigned m_superBinding : 1; 1953 unsigned m_scriptMode: 1; 1954 unsigned m_isArrowFunctionContext : 1; 1955 unsigned m_isClassContext : 1; 1956 unsigned m_constructorKind : 2; 1957 unsigned m_derivedContextType : 2; 1958 unsigned m_needsClassFieldInitializer : 1; 1959 unsigned m_evalContextType : 2; 1960 unsigned m_hasTailCalls : 1; 1961 unsigned m_codeType : 2; 1962 unsigned m_hasCheckpoints : 1; 1963 1964 CodeFeatures m_features; 1965 SourceParseMode m_parseMode; 1966 OptionSet<CodeGenerationMode> m_codeGenerationMode; 1967 1968 unsigned m_lineCount; 1969 unsigned m_endColumn; 1970 1971 int m_numVars; 1972 int m_numCalleeLocals; 1973 int m_numParameters; 1974 1975 CachedMetadataTable m_metadata; 1976 1977 CachedPtr<CachedCodeBlockRareData> m_rareData; 1978 1979 CachedRefPtr<CachedStringImpl> m_sourceURLDirective; 1980 CachedRefPtr<CachedStringImpl> m_sourceMappingURLDirective; 1981 1982 CachedPtr<CachedInstructionStream> m_instructions; 1983 CachedVector<InstructionStream::Offset> m_jumpTargets; 1984 CachedVector<CachedJSValue> m_constantRegisters; 1985 CachedVector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation; 1986 CachedVector<ExpressionRangeInfo> m_expressionInfo; 1987 CachedHashMap<InstructionStream::Offset, int> m_outOfLineJumpTargets; 1988 1989 CachedVector<CachedIdentifier> m_identifiers; 1990 CachedVector<CachedWriteBarrier<CachedFunctionExecutable>> m_functionDecls; 1991 CachedVector<CachedWriteBarrier<CachedFunctionExecutable>> m_functionExprs; 1992 }; 1993 1994 class CachedProgramCodeBlock : public CachedCodeBlock<UnlinkedProgramCodeBlock> { 1995 using Base = CachedCodeBlock<UnlinkedProgramCodeBlock>; 1996 1997 public: 1998 void encode(Encoder& encoder, const UnlinkedProgramCodeBlock& codeBlock) 1999 { 2000 Base::encode(encoder, codeBlock); 2001 m_varDeclarations.encode(encoder, codeBlock.m_varDeclarations); 2002 m_lexicalDeclarations.encode(encoder, codeBlock.m_lexicalDeclarations); 2003 } 2004 2005 UnlinkedProgramCodeBlock* decode(Decoder& decoder) const 2006 { 2007 UnlinkedProgramCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedProgramCodeBlock>(decoder.vm().heap)) UnlinkedProgramCodeBlock(decoder, *this); 2008 codeBlock->finishCreation(decoder.vm()); 2009 Base::decode(decoder, *codeBlock); 2010 m_varDeclarations.decode(decoder, codeBlock->m_varDeclarations); 2011 m_lexicalDeclarations.decode(decoder, codeBlock->m_lexicalDeclarations); 2012 return codeBlock; 2013 } 2014 2015 private: 2016 CachedVariableEnvironment m_varDeclarations; 2017 CachedVariableEnvironment m_lexicalDeclarations; 2018 }; 2019 2020 class CachedModuleCodeBlock : public CachedCodeBlock<UnlinkedModuleProgramCodeBlock> { 2021 using Base = CachedCodeBlock<UnlinkedModuleProgramCodeBlock>; 2022 2023 public: 2024 void encode(Encoder& encoder, const UnlinkedModuleProgramCodeBlock& codeBlock) 2025 { 2026 Base::encode(encoder, codeBlock); 2027 m_moduleEnvironmentSymbolTableConstantRegisterOffset = codeBlock.m_moduleEnvironmentSymbolTableConstantRegisterOffset; 2028 } 2029 2030 UnlinkedModuleProgramCodeBlock* decode(Decoder& decoder) const 2031 { 2032 UnlinkedModuleProgramCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedModuleProgramCodeBlock>(decoder.vm().heap)) UnlinkedModuleProgramCodeBlock(decoder, *this); 2033 codeBlock->finishCreation(decoder.vm()); 2034 Base::decode(decoder, *codeBlock); 2035 codeBlock->m_moduleEnvironmentSymbolTableConstantRegisterOffset = m_moduleEnvironmentSymbolTableConstantRegisterOffset; 2036 return codeBlock; 2037 } 2038 2039 private: 2040 int m_moduleEnvironmentSymbolTableConstantRegisterOffset; 2041 }; 2042 2043 class CachedEvalCodeBlock : public CachedCodeBlock<UnlinkedEvalCodeBlock> { 2044 using Base = CachedCodeBlock<UnlinkedEvalCodeBlock>; 2045 2046 public: 2047 void encode(Encoder& encoder, const UnlinkedEvalCodeBlock& codeBlock) 2048 { 2049 Base::encode(encoder, codeBlock); 2050 m_variables.encode(encoder, codeBlock.m_variables); 2051 m_functionHoistingCandidates.encode(encoder, codeBlock.m_functionHoistingCandidates); 2052 } 2053 2054 UnlinkedEvalCodeBlock* decode(Decoder& decoder) const 2055 { 2056 UnlinkedEvalCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedEvalCodeBlock>(decoder.vm().heap)) UnlinkedEvalCodeBlock(decoder, *this); 2057 codeBlock->finishCreation(decoder.vm()); 2058 Base::decode(decoder, *codeBlock); 2059 m_variables.decode(decoder, codeBlock->m_variables); 2060 m_functionHoistingCandidates.decode(decoder, codeBlock->m_functionHoistingCandidates); 2061 return codeBlock; 2062 } 2063 2064 private: 2065 CachedVector<CachedIdentifier, 0, UnsafeVectorOverflow> m_variables; 2066 CachedVector<CachedIdentifier, 0, UnsafeVectorOverflow> m_functionHoistingCandidates; 2067 }; 2068 2069 class CachedFunctionCodeBlock : public CachedCodeBlock<UnlinkedFunctionCodeBlock> { 2070 using Base = CachedCodeBlock<UnlinkedFunctionCodeBlock>; 2071 2072 public: 2073 void encode(Encoder& encoder, const UnlinkedFunctionCodeBlock& codeBlock) 2074 { 2075 Base::encode(encoder, codeBlock); 2076 } 2077 2078 UnlinkedFunctionCodeBlock* decode(Decoder& decoder) const 2079 { 2080 UnlinkedFunctionCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedFunctionCodeBlock>(decoder.vm().heap)) UnlinkedFunctionCodeBlock(decoder, *this); 2081 codeBlock->finishCreation(decoder.vm()); 2082 Base::decode(decoder, *codeBlock); 2083 return codeBlock; 2084 } 2085 }; 2086 2087 ALWAYS_INLINE UnlinkedFunctionCodeBlock::UnlinkedFunctionCodeBlock(Decoder& decoder, const CachedFunctionCodeBlock& cachedCodeBlock) 2088 : Base(decoder, decoder.vm().unlinkedFunctionCodeBlockStructure.get(), cachedCodeBlock) 2089 { 2090 } 2091 2092 template<typename T> 2093 struct CachedCodeBlockTypeImpl; 2094 2095 enum CachedCodeBlockTag { 2096 CachedProgramCodeBlockTag, 2097 CachedModuleCodeBlockTag, 2098 CachedEvalCodeBlockTag, 2099 }; 2100 2101 static CachedCodeBlockTag tagFromSourceCodeType(SourceCodeType type) 2102 { 2103 switch (type) { 2104 case SourceCodeType::ProgramType: 2105 return CachedProgramCodeBlockTag; 2106 case SourceCodeType::EvalType: 2107 return CachedEvalCodeBlockTag; 2108 case SourceCodeType::ModuleType: 2109 return CachedModuleCodeBlockTag; 2110 case SourceCodeType::FunctionType: 2111 break; 2112 } 2113 ASSERT_NOT_REACHED(); 2114 return static_cast<CachedCodeBlockTag>(-1); 2115 } 2116 2117 template<> 2118 struct CachedCodeBlockTypeImpl<UnlinkedProgramCodeBlock> { 2119 using type = CachedProgramCodeBlock; 2120 static constexpr CachedCodeBlockTag tag = CachedProgramCodeBlockTag; 2121 }; 2122 2123 template<> 2124 struct CachedCodeBlockTypeImpl<UnlinkedModuleProgramCodeBlock> { 2125 using type = CachedModuleCodeBlock; 2126 static constexpr CachedCodeBlockTag tag = CachedModuleCodeBlockTag; 2127 }; 2128 2129 template<> 2130 struct CachedCodeBlockTypeImpl<UnlinkedEvalCodeBlock> { 2131 using type = CachedEvalCodeBlock; 2132 static constexpr CachedCodeBlockTag tag = CachedEvalCodeBlockTag; 2133 }; 2134 2135 template<typename T> 2136 using CachedCodeBlockType = typename CachedCodeBlockTypeImpl<T>::type; 2137 2138 template<typename CodeBlockType> 2139 ALWAYS_INLINE UnlinkedCodeBlock::UnlinkedCodeBlock(Decoder& decoder, Structure* structure, const CachedCodeBlock<CodeBlockType>& cachedCodeBlock) 2140 : Base(decoder.vm(), structure) 2141 , m_thisRegister(cachedCodeBlock.thisRegister()) 2142 , m_scopeRegister(cachedCodeBlock.scopeRegister()) 2143 2144 , m_usesEval(cachedCodeBlock.usesEval()) 2145 , m_isConstructor(cachedCodeBlock.isConstructor()) 2146 , m_hasCapturedVariables(cachedCodeBlock.hasCapturedVariables()) 2147 , m_isBuiltinFunction(cachedCodeBlock.isBuiltinFunction()) 2148 , m_superBinding(cachedCodeBlock.superBinding()) 2149 , m_scriptMode(cachedCodeBlock.scriptMode()) 2150 , m_isArrowFunctionContext(cachedCodeBlock.isArrowFunctionContext()) 2151 , m_isClassContext(cachedCodeBlock.isClassContext()) 2152 , m_hasTailCalls(cachedCodeBlock.hasTailCalls()) 2153 , m_constructorKind(cachedCodeBlock.constructorKind()) 2154 , m_derivedContextType(cachedCodeBlock.derivedContextType()) 2155 , m_evalContextType(cachedCodeBlock.evalContextType()) 2156 , m_codeType(cachedCodeBlock.codeType()) 2157 2158 , m_didOptimize(static_cast<unsigned>(TriState::Indeterminate)) 2159 , m_age(0) 2160 , m_hasCheckpoints(cachedCodeBlock.hasCheckpoints()) 2161 2162 , m_features(cachedCodeBlock.features()) 2163 , m_parseMode(cachedCodeBlock.parseMode()) 2164 , m_codeGenerationMode(cachedCodeBlock.codeGenerationMode()) 2165 2166 , m_lineCount(cachedCodeBlock.lineCount()) 2167 , m_endColumn(cachedCodeBlock.endColumn()) 2168 , m_numVars(cachedCodeBlock.numVars()) 2169 , m_numCalleeLocals(cachedCodeBlock.numCalleeLocals()) 2170 , m_numParameters(cachedCodeBlock.numParameters()) 2171 2172 , m_sourceURLDirective(cachedCodeBlock.sourceURLDirective(decoder)) 2173 , m_sourceMappingURLDirective(cachedCodeBlock.sourceMappingURLDirective(decoder)) 2174 2175 , m_metadata(cachedCodeBlock.metadata(decoder)) 2176 , m_instructions(cachedCodeBlock.instructions(decoder)) 2177 2178 , m_rareData(cachedCodeBlock.rareData(decoder)) 2179 { 2180 } 2181 2182 template<typename CodeBlockType> 2183 ALWAYS_INLINE void CachedCodeBlock<CodeBlockType>::decode(Decoder& decoder, UnlinkedCodeBlock& codeBlock) const 2184 { 2185 m_constantRegisters.decode(decoder, codeBlock.m_constantRegisters, &codeBlock); 2186 m_constantsSourceCodeRepresentation.decode(decoder, codeBlock.m_constantsSourceCodeRepresentation); 2187 m_expressionInfo.decode(decoder, codeBlock.m_expressionInfo); 2188 m_outOfLineJumpTargets.decode(decoder, codeBlock.m_outOfLineJumpTargets); 2189 m_jumpTargets.decode(decoder, codeBlock.m_jumpTargets); 2190 m_identifiers.decode(decoder, codeBlock.m_identifiers); 2191 m_functionDecls.decode(decoder, codeBlock.m_functionDecls, &codeBlock); 2192 m_functionExprs.decode(decoder, codeBlock.m_functionExprs, &codeBlock); 2193 } 2194 2195 ALWAYS_INLINE UnlinkedProgramCodeBlock::UnlinkedProgramCodeBlock(Decoder& decoder, const CachedProgramCodeBlock& cachedCodeBlock) 2196 : Base(decoder, decoder.vm().unlinkedProgramCodeBlockStructure.get(), cachedCodeBlock) 2197 { 2198 } 2199 2200 ALWAYS_INLINE UnlinkedModuleProgramCodeBlock::UnlinkedModuleProgramCodeBlock(Decoder& decoder, const CachedModuleCodeBlock& cachedCodeBlock) 2201 : Base(decoder, decoder.vm().unlinkedModuleProgramCodeBlockStructure.get(), cachedCodeBlock) 2202 { 2203 } 2204 2205 ALWAYS_INLINE UnlinkedEvalCodeBlock::UnlinkedEvalCodeBlock(Decoder& decoder, const CachedEvalCodeBlock& cachedCodeBlock) 2206 : Base(decoder, decoder.vm().unlinkedEvalCodeBlockStructure.get(), cachedCodeBlock) 2207 { 2208 } 2209 2210 ALWAYS_INLINE void CachedFunctionExecutable::encode(Encoder& encoder, const UnlinkedFunctionExecutable& executable) 2211 { 2212 m_mutableMetadata.m_features = executable.m_features; 2213 m_mutableMetadata.m_hasCapturedVariables = executable.m_hasCapturedVariables; 2214 2215 m_firstLineOffset = executable.m_firstLineOffset; 2216 m_lineCount = executable.m_lineCount; 2217 m_unlinkedFunctionNameStart = executable.m_unlinkedFunctionNameStart; 2218 m_unlinkedBodyStartColumn = executable.m_unlinkedBodyStartColumn; 2219 m_unlinkedBodyEndColumn = executable.m_unlinkedBodyEndColumn; 2220 m_startOffset = executable.m_startOffset; 2221 m_sourceLength = executable.m_sourceLength; 2222 m_parametersStartOffset = executable.m_parametersStartOffset; 2223 m_typeProfilingStartOffset = executable.m_typeProfilingStartOffset; 2224 m_typeProfilingEndOffset = executable.m_typeProfilingEndOffset; 2225 m_parameterCount = executable.m_parameterCount; 2226 2227 m_sourceParseMode = executable.m_sourceParseMode; 2228 2229 m_isInStrictContext = executable.m_isInStrictContext; 2230 m_isBuiltinFunction = executable.m_isBuiltinFunction; 2231 m_isBuiltinDefaultClassConstructor = executable.m_isBuiltinDefaultClassConstructor; 2232 m_constructAbility = executable.m_constructAbility; 2233 m_constructorKind = executable.m_constructorKind; 2234 m_functionMode = executable.m_functionMode; 2235 m_scriptMode = executable.m_scriptMode; 2236 m_superBinding = executable.m_superBinding; 2237 m_derivedContextType = executable.m_derivedContextType; 2238 m_needsClassFieldInitializer = executable.m_needsClassFieldInitializer; 2239 2240 m_rareData.encode(encoder, executable.m_rareData.get()); 2241 2242 m_name.encode(encoder, executable.name()); 2243 m_ecmaName.encode(encoder, executable.ecmaName()); 2244 2245 m_unlinkedCodeBlockForCall.encode(encoder, executable.m_unlinkedCodeBlockForCall); 2246 m_unlinkedCodeBlockForConstruct.encode(encoder, executable.m_unlinkedCodeBlockForConstruct); 2247 2248 if (!executable.m_unlinkedCodeBlockForCall || !executable.m_unlinkedCodeBlockForConstruct) 2249 encoder.addLeafExecutable(&executable, encoder.offsetOf(this)); 2250 } 2251 2252 ALWAYS_INLINE UnlinkedFunctionExecutable* CachedFunctionExecutable::decode(Decoder& decoder) const 2253 { 2254 UnlinkedFunctionExecutable* executable = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(decoder.vm().heap)) UnlinkedFunctionExecutable(decoder, *this); 2255 executable->finishCreation(decoder.vm()); 2256 return executable; 2257 } 2258 2259 ALWAYS_INLINE UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(Decoder& decoder, const CachedFunctionExecutable& cachedExecutable) 2260 : Base(decoder.vm(), decoder.vm().unlinkedFunctionExecutableStructure.get()) 2261 , m_firstLineOffset(cachedExecutable.firstLineOffset()) 2262 , m_isInStrictContext(cachedExecutable.isInStrictContext()) 2263 , m_lineCount(cachedExecutable.lineCount()) 2264 , m_hasCapturedVariables(cachedExecutable.hasCapturedVariables()) 2265 , m_unlinkedFunctionNameStart(cachedExecutable.unlinkedFunctionNameStart()) 2266 , m_isBuiltinFunction(cachedExecutable.isBuiltinFunction()) 2267 , m_unlinkedBodyStartColumn(cachedExecutable.unlinkedBodyStartColumn()) 2268 , m_isBuiltinDefaultClassConstructor(cachedExecutable.isBuiltinDefaultClassConstructor()) 2269 , m_unlinkedBodyEndColumn(cachedExecutable.unlinkedBodyEndColumn()) 2270 , m_constructAbility(cachedExecutable.constructAbility()) 2271 , m_startOffset(cachedExecutable.startOffset()) 2272 , m_scriptMode(cachedExecutable.scriptMode()) 2273 , m_sourceLength(cachedExecutable.sourceLength()) 2274 , m_superBinding(cachedExecutable.superBinding()) 2275 , m_parametersStartOffset(cachedExecutable.parametersStartOffset()) 2276 , m_isCached(false) 2277 , m_typeProfilingStartOffset(cachedExecutable.typeProfilingStartOffset()) 2278 , m_typeProfilingEndOffset(cachedExecutable.typeProfilingEndOffset()) 2279 , m_parameterCount(cachedExecutable.parameterCount()) 2280 , m_features(cachedExecutable.features()) 2281 , m_sourceParseMode(cachedExecutable.sourceParseMode()) 2282 , m_constructorKind(cachedExecutable.constructorKind()) 2283 , m_functionMode(cachedExecutable.functionMode()) 2284 , m_derivedContextType(cachedExecutable.derivedContextType()) 2285 , m_isGeneratedFromCache(true) 2286 , m_needsClassFieldInitializer(cachedExecutable.needsClassFieldInitializer()) 2287 , m_unlinkedCodeBlockForCall() 2288 , m_unlinkedCodeBlockForConstruct() 2289 2290 , m_name(cachedExecutable.name(decoder)) 2291 , m_ecmaName(cachedExecutable.ecmaName(decoder)) 2292 2293 , m_rareData(cachedExecutable.rareData(decoder)) 2294 { 2295 2296 uint32_t leafExecutables = 2; 2297 auto checkBounds = [&](int32_t& codeBlockOffset, auto& cachedPtr) { 2298 if (!cachedPtr.isEmpty()) { 2299 ptrdiff_t offset = decoder.offsetOf(&cachedPtr); 2300 if (static_cast<size_t>(offset) < decoder.size()) { 2301 codeBlockOffset = offset; 2302 m_isCached = true; 2303 leafExecutables--; 2304 return; 2305 } 2306 } 2307 2308 codeBlockOffset = 0; 2309 }; 2310 2311 if (!cachedExecutable.unlinkedCodeBlockForCall().isEmpty() || !cachedExecutable.unlinkedCodeBlockForConstruct().isEmpty()) { 2312 checkBounds(m_cachedCodeBlockForCallOffset, cachedExecutable.unlinkedCodeBlockForCall()); 2313 checkBounds(m_cachedCodeBlockForConstructOffset, cachedExecutable.unlinkedCodeBlockForConstruct()); 2314 if (m_isCached) 2315 m_decoder = &decoder; 2316 else 2317 m_decoder = nullptr; 2318 } 2319 2320 if (leafExecutables) 2321 decoder.addLeafExecutable(this, decoder.offsetOf(&cachedExecutable)); 2322 } 2323 2324 template<typename CodeBlockType> 2325 ALWAYS_INLINE void CachedCodeBlock<CodeBlockType>::encode(Encoder& encoder, const UnlinkedCodeBlock& codeBlock) 2326 { 2327 m_thisRegister = codeBlock.m_thisRegister; 2328 m_scopeRegister = codeBlock.m_scopeRegister; 2329 m_usesEval = codeBlock.m_usesEval; 2330 m_isConstructor = codeBlock.m_isConstructor; 2331 m_hasCapturedVariables = codeBlock.m_hasCapturedVariables; 2332 m_isBuiltinFunction = codeBlock.m_isBuiltinFunction; 2333 m_superBinding = codeBlock.m_superBinding; 2334 m_scriptMode = codeBlock.m_scriptMode; 2335 m_isArrowFunctionContext = codeBlock.m_isArrowFunctionContext; 2336 m_isClassContext = codeBlock.m_isClassContext; 2337 m_hasTailCalls = codeBlock.m_hasTailCalls; 2338 m_constructorKind = codeBlock.m_constructorKind; 2339 m_derivedContextType = codeBlock.m_derivedContextType; 2340 m_evalContextType = codeBlock.m_evalContextType; 2341 m_lineCount = codeBlock.m_lineCount; 2342 m_endColumn = codeBlock.m_endColumn; 2343 m_numVars = codeBlock.m_numVars; 2344 m_numCalleeLocals = codeBlock.m_numCalleeLocals; 2345 m_numParameters = codeBlock.m_numParameters; 2346 m_features = codeBlock.m_features; 2347 m_parseMode = codeBlock.m_parseMode; 2348 m_codeGenerationMode = codeBlock.m_codeGenerationMode; 2349 m_codeType = codeBlock.m_codeType; 2350 m_hasCheckpoints = codeBlock.m_hasCheckpoints; 2351 2352 m_metadata.encode(encoder, codeBlock.m_metadata.get()); 2353 m_rareData.encode(encoder, codeBlock.m_rareData.get()); 2354 2355 m_sourceURLDirective.encode(encoder, codeBlock.m_sourceURLDirective.get()); 2356 m_sourceMappingURLDirective.encode(encoder, codeBlock.m_sourceURLDirective.get()); 2357 2358 m_instructions.encode(encoder, codeBlock.m_instructions.get()); 2359 m_constantRegisters.encode(encoder, codeBlock.m_constantRegisters); 2360 m_constantsSourceCodeRepresentation.encode(encoder, codeBlock.m_constantsSourceCodeRepresentation); 2361 m_expressionInfo.encode(encoder, codeBlock.m_expressionInfo); 2362 m_jumpTargets.encode(encoder, codeBlock.m_jumpTargets); 2363 m_outOfLineJumpTargets.encode(encoder, codeBlock.m_outOfLineJumpTargets); 2364 2365 m_identifiers.encode(encoder, codeBlock.m_identifiers); 2366 m_functionDecls.encode(encoder, codeBlock.m_functionDecls); 2367 m_functionExprs.encode(encoder, codeBlock.m_functionExprs); 2368 } 2369 2370 class CachedSourceCodeKey : public CachedObject<SourceCodeKey> { 2371 public: 2372 void encode(Encoder& encoder, const SourceCodeKey& key) 2373 { 2374 m_sourceCode.encode(encoder, key.m_sourceCode); 2375 m_name.encode(encoder, key.m_name); 2376 m_flags = key.m_flags.m_flags; 2377 m_hash = key.hash(); 2378 m_functionConstructorParametersEndPosition = key.m_functionConstructorParametersEndPosition; 2379 } 2380 2381 void decode(Decoder& decoder, SourceCodeKey& key) const 2382 { 2383 m_sourceCode.decode(decoder, key.m_sourceCode); 2384 m_name.decode(decoder, key.m_name); 2385 key.m_flags.m_flags = m_flags; 2386 key.m_hash = m_hash; 2387 key.m_functionConstructorParametersEndPosition = m_functionConstructorParametersEndPosition; 2388 } 2389 2390 private: 2391 CachedUnlinkedSourceCode m_sourceCode; 2392 CachedString m_name; 2393 unsigned m_flags; 2394 unsigned m_hash; 2395 int m_functionConstructorParametersEndPosition; 2396 }; 2397 2398 class GenericCacheEntry { 2399 public: 2400 bool decode(Decoder&, std::pair<SourceCodeKey, UnlinkedCodeBlock*>&) const; 2401 bool isStillValid(Decoder&, const SourceCodeKey&, CachedCodeBlockTag) const; 2402 2403 protected: 2404 GenericCacheEntry(Encoder& encoder, CachedCodeBlockTag tag) 2405 : m_tag(tag) 2406 { 2407 m_bootSessionUUID.encode(encoder, bootSessionUUIDString()); 2408 } 2409 2410 CachedCodeBlockTag tag() const { return m_tag; } 2411 2412 bool isUpToDate(Decoder& decoder) const 2413 { 2414 if (m_cacheVersion != jscBytecodeCacheVersion()) 2415 return false; 2416 if (m_bootSessionUUID.decode(decoder) != bootSessionUUIDString()) 2417 return false; 2418 return true; 2419 } 2420 2421 private: 2422 uint32_t m_cacheVersion { jscBytecodeCacheVersion() }; 2423 CachedString m_bootSessionUUID; 2424 CachedCodeBlockTag m_tag; 2425 }; 2426 2427 static_assert(alignof(GenericCacheEntry) <= alignof(std::max_align_t)); 2428 2429 template<typename UnlinkedCodeBlockType> 2430 class CacheEntry : public GenericCacheEntry { 2431 public: 2432 CacheEntry(Encoder& encoder) 2433 : GenericCacheEntry(encoder, CachedCodeBlockTypeImpl<UnlinkedCodeBlockType>::tag) 2434 { 2435 } 2436 2437 void encode(Encoder& encoder, std::pair<SourceCodeKey, const UnlinkedCodeBlockType*> pair) 2438 { 2439 m_key.encode(encoder, pair.first); 2440 m_codeBlock.encode(encoder, pair.second); 2441 } 2442 2443 private: 2444 friend GenericCacheEntry; 2445 2446 bool isStillValid(Decoder& decoder, const SourceCodeKey& key) const 2447 { 2448 SourceCodeKey decodedKey; 2449 m_key.decode(decoder, decodedKey); 2450 return decodedKey == key; 2451 } 2452 2453 bool decode(Decoder& decoder, std::pair<SourceCodeKey, UnlinkedCodeBlockType*>& result) const 2454 { 2455 ASSERT(tag() == CachedCodeBlockTypeImpl<UnlinkedCodeBlockType>::tag); 2456 SourceCodeKey decodedKey; 2457 m_key.decode(decoder, decodedKey); 2458 result = { WTFMove(decodedKey), m_codeBlock.decode(decoder) }; 2459 return true; 2460 } 2461 2462 CachedSourceCodeKey m_key; 2463 CachedPtr<CachedCodeBlockType<UnlinkedCodeBlockType>> m_codeBlock; 2464 }; 2465 2466 static_assert(alignof(CacheEntry<UnlinkedProgramCodeBlock>) <= alignof(std::max_align_t)); 2467 static_assert(alignof(CacheEntry<UnlinkedModuleProgramCodeBlock>) <= alignof(std::max_align_t)); 2468 2469 bool GenericCacheEntry::decode(Decoder& decoder, std::pair<SourceCodeKey, UnlinkedCodeBlock*>& result) const 2470 { 2471 if (!isUpToDate(decoder)) 2472 return false; 2473 2474 switch (m_tag) { 2475 case CachedProgramCodeBlockTag: 2476 return bitwise_cast<const CacheEntry<UnlinkedProgramCodeBlock>*>(this)->decode(decoder, reinterpret_cast<std::pair<SourceCodeKey, UnlinkedProgramCodeBlock*>&>(result)); 2477 case CachedModuleCodeBlockTag: 2478 return bitwise_cast<const CacheEntry<UnlinkedModuleProgramCodeBlock>*>(this)->decode(decoder, reinterpret_cast<std::pair<SourceCodeKey, UnlinkedModuleProgramCodeBlock*>&>(result)); 2479 case CachedEvalCodeBlockTag: 2480 // We do not cache eval code blocks 2481 RELEASE_ASSERT_NOT_REACHED(); 2482 } 2483 RELEASE_ASSERT_NOT_REACHED(); 2484 #if COMPILER(MSVC) 2485 // Without this, MSVC will complain that this path does not return a value. 2486 return false; 2487 #endif 2488 } 2489 2490 bool GenericCacheEntry::isStillValid(Decoder& decoder, const SourceCodeKey& key, CachedCodeBlockTag tag) const 2491 { 2492 if (!isUpToDate(decoder)) 2493 return false; 2494 2495 switch (tag) { 2496 case CachedProgramCodeBlockTag: 2497 return bitwise_cast<const CacheEntry<UnlinkedProgramCodeBlock>*>(this)->isStillValid(decoder, key); 2498 case CachedModuleCodeBlockTag: 2499 return bitwise_cast<const CacheEntry<UnlinkedModuleProgramCodeBlock>*>(this)->isStillValid(decoder, key); 2500 case CachedEvalCodeBlockTag: 2501 // We do not cache eval code blocks 2502 RELEASE_ASSERT_NOT_REACHED(); 2503 } 2504 RELEASE_ASSERT_NOT_REACHED(); 2505 return false; 2506 } 2507 2508 template<typename UnlinkedCodeBlockType> 2509 void encodeCodeBlock(Encoder& encoder, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock) 2510 { 2511 auto* entry = encoder.template malloc<CacheEntry<UnlinkedCodeBlockType>>(encoder); 2512 entry->encode(encoder, { key, jsCast<const UnlinkedCodeBlockType*>(codeBlock) }); 2513 } 2514 2515 RefPtr<CachedBytecode> encodeCodeBlock(VM& vm, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock, FileSystem::PlatformFileHandle fd, BytecodeCacheError& error) 2516 { 2517 const ClassInfo* classInfo = codeBlock->classInfo(vm); 2518 2519 Encoder encoder(vm, fd); 2520 if (classInfo == UnlinkedProgramCodeBlock::info()) 2521 encodeCodeBlock<UnlinkedProgramCodeBlock>(encoder, key, codeBlock); 2522 else if (classInfo == UnlinkedModuleProgramCodeBlock::info()) 2523 encodeCodeBlock<UnlinkedModuleProgramCodeBlock>(encoder, key, codeBlock); 2524 else 2525 ASSERT(classInfo == UnlinkedEvalCodeBlock::info()); 2526 2527 return encoder.release(error); 2528 } 2529 2530 RefPtr<CachedBytecode> encodeCodeBlock(VM& vm, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock) 2531 { 2532 BytecodeCacheError error; 2533 return encodeCodeBlock(vm, key, codeBlock, FileSystem::invalidPlatformFileHandle, error); 2534 } 2535 2536 RefPtr<CachedBytecode> encodeFunctionCodeBlock(VM& vm, const UnlinkedFunctionCodeBlock* codeBlock, BytecodeCacheError& error) 2537 { 2538 Encoder encoder(vm); 2539 encoder.malloc<CachedFunctionCodeBlock>()->encode(encoder, *codeBlock); 2540 return encoder.release(error); 2541 } 2542 2543 UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, Ref<CachedBytecode> cachedBytecode) 2544 { 2545 const auto* cachedEntry = bitwise_cast<const GenericCacheEntry*>(cachedBytecode->data()); 2546 Ref<Decoder> decoder = Decoder::create(vm, WTFMove(cachedBytecode), &key.source().provider()); 2547 std::pair<SourceCodeKey, UnlinkedCodeBlock*> entry; 2548 { 2549 DeferGC deferGC(vm.heap); 2550 if (!cachedEntry->decode(decoder.get(), entry)) 2551 return nullptr; 2552 } 2553 2554 if (entry.first != key) 2555 return nullptr; 2556 return entry.second; 2557 } 2558 2559 bool isCachedBytecodeStillValid(VM& vm, Ref<CachedBytecode> cachedBytecode, const SourceCodeKey& key, SourceCodeType type) 2560 { 2561 const void* buffer = cachedBytecode->data(); 2562 size_t size = cachedBytecode->size(); 2563 if (!size) 2564 return false; 2565 const auto* cachedEntry = bitwise_cast<const GenericCacheEntry*>(buffer); 2566 Ref<Decoder> decoder = Decoder::create(vm, WTFMove(cachedBytecode)); 2567 return cachedEntry->isStillValid(decoder.get(), key, tagFromSourceCodeType(type)); 2568 } 2569 2570 void decodeFunctionCodeBlock(Decoder& decoder, int32_t cachedFunctionCodeBlockOffset, WriteBarrier<UnlinkedFunctionCodeBlock>& codeBlock, const JSCell* owner) 2571 { 2572 ASSERT(decoder.vm().heap.isDeferred()); 2573 auto* cachedCodeBlock = static_cast<const CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock>*>(decoder.ptrForOffsetFromBase(cachedFunctionCodeBlockOffset)); 2574 cachedCodeBlock->decode(decoder, codeBlock, owner); 2575 } 2576 2577 } // namespace JSC