1/*
2 * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "JSCast.h"
29#include "ParserModes.h"
30#include "VariableEnvironment.h"
31#include <wtf/HashMap.h>
32#include <wtf/MallocPtr.h>
33
34namespace JSC {
35
36class CachedBytecode;
37class SourceCodeKey;
38class UnlinkedCodeBlock;
39class UnlinkedFunctionCodeBlock;
40
41enum class SourceCodeType;
42
43// This struct has to be updated when incrementally writing to the bytecode
44// cache, since this will only be filled in when we parse the function
45struct CachedFunctionExecutableMetadata {
46 CodeFeatures m_features;
47 bool m_hasCapturedVariables;
48};
49
50struct CachedFunctionExecutableOffsets {
51 static ptrdiff_t codeBlockForCallOffset();
52 static ptrdiff_t codeBlockForConstructOffset();
53 static ptrdiff_t metadataOffset();
54};
55
56struct CachedWriteBarrierOffsets {
57 static ptrdiff_t ptrOffset();
58};
59
60struct CachedPtrOffsets {
61 static ptrdiff_t offsetOffset();
62};
63
64class VariableLengthObjectBase {
65 friend class CachedBytecode;
66
67protected:
68 VariableLengthObjectBase(ptrdiff_t offset)
69 : m_offset(offset)
70 {
71 }
72
73 ptrdiff_t m_offset;
74};
75
76class Decoder : public RefCounted<Decoder> {
77 WTF_MAKE_NONCOPYABLE(Decoder);
78
79public:
80 static Ref<Decoder> create(VM&, Ref<CachedBytecode>, RefPtr<SourceProvider> = nullptr);
81
82 ~Decoder();
83
84 VM& vm() { return m_vm; }
85 size_t size() const;
86
87 ptrdiff_t offsetOf(const void*);
88 void cacheOffset(ptrdiff_t, void*);
89 WTF::Optional<void*> cachedPtrForOffset(ptrdiff_t);
90 const void* ptrForOffsetFromBase(ptrdiff_t);
91 CompactVariableMap::Handle handleForEnvironment(CompactVariableEnvironment*) const;
92 void setHandleForEnvironment(CompactVariableEnvironment*, const CompactVariableMap::Handle&);
93 void addLeafExecutable(const UnlinkedFunctionExecutable*, ptrdiff_t);
94 RefPtr<SourceProvider> provider() const;
95
96 template<typename Functor>
97 void addFinalizer(const Functor&);
98
99private:
100 Decoder(VM&, Ref<CachedBytecode>, RefPtr<SourceProvider>);
101
102 VM& m_vm;
103 Ref<CachedBytecode> m_cachedBytecode;
104 HashMap<ptrdiff_t, void*> m_offsetToPtrMap;
105 Vector<std::function<void()>> m_finalizers;
106 HashMap<CompactVariableEnvironment*, CompactVariableMap::Handle> m_environmentToHandleMap;
107 RefPtr<SourceProvider> m_provider;
108};
109
110JS_EXPORT_PRIVATE Ref<CachedBytecode> encodeCodeBlock(VM&, const SourceCodeKey&, const UnlinkedCodeBlock*);
111
112UnlinkedCodeBlock* decodeCodeBlockImpl(VM&, const SourceCodeKey&, Ref<CachedBytecode>);
113
114template<typename UnlinkedCodeBlockType>
115UnlinkedCodeBlockType* decodeCodeBlock(VM& vm, const SourceCodeKey& key, Ref<CachedBytecode> cachedBytecode)
116{
117 return jsCast<UnlinkedCodeBlockType*>(decodeCodeBlockImpl(vm, key, WTFMove(cachedBytecode)));
118}
119
120JS_EXPORT_PRIVATE Ref<CachedBytecode> encodeFunctionCodeBlock(VM&, const UnlinkedFunctionCodeBlock*);
121
122JS_EXPORT_PRIVATE void decodeFunctionCodeBlock(Decoder&, int32_t cachedFunctionCodeBlockOffset, WriteBarrier<UnlinkedFunctionCodeBlock>&, const JSCell*);
123
124bool isCachedBytecodeStillValid(VM&, Ref<CachedBytecode>, const SourceCodeKey&, SourceCodeType);
125
126} // namespace JSC
127