WebAssembly: perform stack checks
[WebKit-https.git] / Source / JavaScriptCore / llint / LLIntData.cpp
1 /*
2  * Copyright (C) 2011, 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "LLIntData.h"
28
29 #include "ArithProfile.h"
30 #include "BytecodeConventions.h"
31 #include "CodeBlock.h"
32 #include "CodeType.h"
33 #include "InitializeThreading.h"
34 #include "Instruction.h"
35 #include "JSScope.h"
36 #include "LLIntCLoop.h"
37 #include "LLIntCommon.h"
38 #include "MaxFrameExtentForSlowPathCall.h"
39 #include "Opcode.h"
40 #include "PropertyOffset.h"
41 #include "ShadowChicken.h"
42 #include "WriteBarrier.h"
43 #include <string>
44 #include <wtf/NeverDestroyed.h>
45
46 #define STATIC_ASSERT(cond) static_assert(cond, "LLInt assumes " #cond)
47
48 namespace JSC { namespace LLInt {
49
50 Instruction* Data::s_exceptionInstructions = 0;
51 Opcode Data::s_opcodeMap[numOpcodeIDs] = { };
52 OpcodeStatsArray* Data::s_opcodeStatsArray = nullptr;
53
54 #if ENABLE(JIT)
55 extern "C" void llint_entry(void*);
56 #endif
57
58 void initialize()
59 {
60     Data::s_exceptionInstructions = new Instruction[maxOpcodeLength + 1];
61
62 #if !ENABLE(JIT)
63     CLoop::initialize();
64
65 #else // ENABLE(JIT)
66     llint_entry(&Data::s_opcodeMap);
67
68     for (int i = 0; i < maxOpcodeLength + 1; ++i)
69         Data::s_exceptionInstructions[i].u.pointer =
70             LLInt::getCodePtr(llint_throw_from_slow_path_trampoline);
71 #endif // ENABLE(JIT)
72
73 #if ENABLE(LLINT_STATS)
74     Data::ensureStats();
75 #endif
76 }
77
78 #if COMPILER(CLANG)
79 #pragma clang diagnostic push
80 #pragma clang diagnostic ignored "-Wmissing-noreturn"
81 #endif
82 void Data::performAssertions(VM& vm)
83 {
84     UNUSED_PARAM(vm);
85     
86     // Assertions to match LowLevelInterpreter.asm.  If you change any of this code, be
87     // prepared to change LowLevelInterpreter.asm as well!!
88
89 #if USE(JSVALUE64)
90     const ptrdiff_t PtrSize = 8;
91     const ptrdiff_t CallFrameHeaderSlots = 5;
92 #else // USE(JSVALUE64) // i.e. 32-bit version
93     const ptrdiff_t PtrSize = 4;
94     const ptrdiff_t CallFrameHeaderSlots = 4;
95 #endif
96     const ptrdiff_t SlotSize = 8;
97
98     STATIC_ASSERT(sizeof(void*) == PtrSize);
99     STATIC_ASSERT(sizeof(Register) == SlotSize);
100     STATIC_ASSERT(CallFrame::headerSizeInRegisters == CallFrameHeaderSlots);
101
102     ASSERT(!CallFrame::callerFrameOffset());
103     STATIC_ASSERT(CallerFrameAndPC::sizeInRegisters == (PtrSize * 2) / SlotSize);
104     ASSERT(CallFrame::returnPCOffset() == CallFrame::callerFrameOffset() + PtrSize);
105     ASSERT(CallFrameSlot::codeBlock * sizeof(Register) == CallFrame::returnPCOffset() + PtrSize);
106     STATIC_ASSERT(CallFrameSlot::callee * sizeof(Register) == CallFrameSlot::codeBlock * sizeof(Register) + SlotSize);
107     STATIC_ASSERT(CallFrameSlot::argumentCount * sizeof(Register) == CallFrameSlot::callee * sizeof(Register) + SlotSize);
108     STATIC_ASSERT(CallFrameSlot::thisArgument * sizeof(Register) == CallFrameSlot::argumentCount * sizeof(Register) + SlotSize);
109     STATIC_ASSERT(CallFrame::headerSizeInRegisters == CallFrameSlot::thisArgument);
110
111     ASSERT(CallFrame::argumentOffsetIncludingThis(0) == CallFrameSlot::thisArgument);
112
113 #if CPU(BIG_ENDIAN)
114     ASSERT(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag) == 0);
115     ASSERT(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload) == 4);
116 #else
117     ASSERT(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag) == 4);
118     ASSERT(OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload) == 0);
119 #endif
120 #if USE(JSVALUE32_64)
121     STATIC_ASSERT(JSValue::Int32Tag == static_cast<unsigned>(-1));
122     STATIC_ASSERT(JSValue::BooleanTag == static_cast<unsigned>(-2));
123     STATIC_ASSERT(JSValue::NullTag == static_cast<unsigned>(-3));
124     STATIC_ASSERT(JSValue::UndefinedTag == static_cast<unsigned>(-4));
125     STATIC_ASSERT(JSValue::CellTag == static_cast<unsigned>(-5));
126     STATIC_ASSERT(JSValue::EmptyValueTag == static_cast<unsigned>(-6));
127     STATIC_ASSERT(JSValue::DeletedValueTag == static_cast<unsigned>(-7));
128     STATIC_ASSERT(JSValue::LowestTag == static_cast<unsigned>(-7));
129 #else
130     STATIC_ASSERT(TagBitTypeOther == 0x2);
131     STATIC_ASSERT(TagBitBool == 0x4);
132     STATIC_ASSERT(TagBitUndefined == 0x8);
133     STATIC_ASSERT(ValueEmpty == 0x0);
134     STATIC_ASSERT(ValueFalse == (TagBitTypeOther | TagBitBool));
135     STATIC_ASSERT(ValueTrue == (TagBitTypeOther | TagBitBool | 1));
136     STATIC_ASSERT(ValueUndefined == (TagBitTypeOther | TagBitUndefined));
137     STATIC_ASSERT(ValueNull == TagBitTypeOther);
138 #endif
139 #if (CPU(X86_64) && !OS(WINDOWS)) || CPU(ARM64) || !ENABLE(JIT)
140     STATIC_ASSERT(!maxFrameExtentForSlowPathCall);
141 #elif CPU(ARM)
142     STATIC_ASSERT(maxFrameExtentForSlowPathCall == 24);
143 #elif CPU(X86) || CPU(MIPS)
144     STATIC_ASSERT(maxFrameExtentForSlowPathCall == 40);
145 #elif CPU(X86_64) && OS(WINDOWS)
146     STATIC_ASSERT(maxFrameExtentForSlowPathCall == 64);
147 #endif
148
149 #if !ENABLE(JIT) || USE(JSVALUE32_64)
150     ASSERT(!CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters());
151 #elif (CPU(X86_64) && !OS(WINDOWS))  || CPU(ARM64)
152     ASSERT(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters() == 3);
153 #elif (CPU(X86_64) && OS(WINDOWS))
154     ASSERT(CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters() == 3);
155 #endif
156     
157     STATIC_ASSERT(StringType == 6);
158     STATIC_ASSERT(SymbolType == 7);
159     STATIC_ASSERT(ObjectType == 23);
160     STATIC_ASSERT(FinalObjectType == 24);
161     STATIC_ASSERT(JSFunctionType == 26);
162     STATIC_ASSERT(ArrayType == 34);
163     STATIC_ASSERT(DerivedArrayType == 35);
164     STATIC_ASSERT(ProxyObjectType == 53);
165     STATIC_ASSERT(Int8ArrayType == 36);
166     STATIC_ASSERT(Int16ArrayType == 37);
167     STATIC_ASSERT(Int32ArrayType == 38);
168     STATIC_ASSERT(Uint8ArrayType == 39);
169     STATIC_ASSERT(Uint8ClampedArrayType == 40);
170     STATIC_ASSERT(Uint16ArrayType == 41);
171     STATIC_ASSERT(Uint32ArrayType == 42);
172     STATIC_ASSERT(Float32ArrayType == 43);
173     STATIC_ASSERT(Float64ArrayType == 44);
174     STATIC_ASSERT(MasqueradesAsUndefined == 1);
175     STATIC_ASSERT(ImplementsDefaultHasInstance == 2);
176     STATIC_ASSERT(FirstConstantRegisterIndex == 0x40000000);
177     STATIC_ASSERT(GlobalCode == 0);
178     STATIC_ASSERT(EvalCode == 1);
179     STATIC_ASSERT(FunctionCode == 2);
180     STATIC_ASSERT(ModuleCode == 3);
181     
182     STATIC_ASSERT(IsArray == 0x01);
183     STATIC_ASSERT(IndexingShapeMask == 0x0E);
184     STATIC_ASSERT(NoIndexingShape == 0x00);
185     STATIC_ASSERT(Int32Shape == 0x04);
186     STATIC_ASSERT(DoubleShape == 0x06);
187     STATIC_ASSERT(ContiguousShape == 0x08);
188     STATIC_ASSERT(ArrayStorageShape == 0x0A);
189     STATIC_ASSERT(SlowPutArrayStorageShape == 0x0C);
190
191     ASSERT(!(reinterpret_cast<ptrdiff_t>((reinterpret_cast<WriteBarrier<JSCell>*>(0x4000)->slot())) - 0x4000));
192     static_assert(PutByIdPrimaryTypeMask == 0x6, "LLInt assumes PutByIdPrimaryTypeMask is == 0x6");
193     static_assert(PutByIdPrimaryTypeSecondary == 0x0, "LLInt assumes PutByIdPrimaryTypeSecondary is == 0x0");
194     static_assert(PutByIdPrimaryTypeObjectWithStructure == 0x2, "LLInt assumes PutByIdPrimaryTypeObjectWithStructure is == 0x2");
195     static_assert(PutByIdPrimaryTypeObjectWithStructureOrOther == 0x4, "LLInt assumes PutByIdPrimaryTypeObjectWithStructureOrOther is == 0x4");
196     static_assert(PutByIdSecondaryTypeMask == -0x8, "LLInt assumes PutByIdSecondaryTypeMask is == -0x8");
197     static_assert(PutByIdSecondaryTypeBottom == 0x0, "LLInt assumes PutByIdSecondaryTypeBottom is == 0x0");
198     static_assert(PutByIdSecondaryTypeBoolean == 0x8, "LLInt assumes PutByIdSecondaryTypeBoolean is == 0x8");
199     static_assert(PutByIdSecondaryTypeOther == 0x10, "LLInt assumes PutByIdSecondaryTypeOther is == 0x10");
200     static_assert(PutByIdSecondaryTypeInt32 == 0x18, "LLInt assumes PutByIdSecondaryTypeInt32 is == 0x18");
201     static_assert(PutByIdSecondaryTypeNumber == 0x20, "LLInt assumes PutByIdSecondaryTypeNumber is == 0x20");
202     static_assert(PutByIdSecondaryTypeString == 0x28, "LLInt assumes PutByIdSecondaryTypeString is == 0x28");
203     static_assert(PutByIdSecondaryTypeSymbol == 0x30, "LLInt assumes PutByIdSecondaryTypeSymbol is == 0x30");
204     static_assert(PutByIdSecondaryTypeObject == 0x38, "LLInt assumes PutByIdSecondaryTypeObject is == 0x38");
205     static_assert(PutByIdSecondaryTypeObjectOrOther == 0x40, "LLInt assumes PutByIdSecondaryTypeObjectOrOther is == 0x40");
206     static_assert(PutByIdSecondaryTypeTop == 0x48, "LLInt assumes PutByIdSecondaryTypeTop is == 0x48");
207
208     static_assert(GlobalProperty == 0, "LLInt assumes GlobalProperty ResultType is == 0");
209     static_assert(GlobalVar == 1, "LLInt assumes GlobalVar ResultType is == 1");
210     static_assert(GlobalLexicalVar == 2, "LLInt assumes GlobalLexicalVar ResultType is == 2");
211     static_assert(ClosureVar == 3, "LLInt assumes ClosureVar ResultType is == 3");
212     static_assert(LocalClosureVar == 4, "LLInt assumes LocalClosureVar ResultType is == 4");
213     static_assert(ModuleVar == 5, "LLInt assumes ModuleVar ResultType is == 5");
214     static_assert(GlobalPropertyWithVarInjectionChecks == 6, "LLInt assumes GlobalPropertyWithVarInjectionChecks ResultType is == 6");
215     static_assert(GlobalVarWithVarInjectionChecks == 7, "LLInt assumes GlobalVarWithVarInjectionChecks ResultType is == 7");
216     static_assert(GlobalLexicalVarWithVarInjectionChecks == 8, "LLInt assumes GlobalLexicalVarWithVarInjectionChecks ResultType is == 8");
217     static_assert(ClosureVarWithVarInjectionChecks == 9, "LLInt assumes ClosureVarWithVarInjectionChecks ResultType is == 9");
218
219     static_assert(static_cast<unsigned>(InitializationMode::NotInitialization) == 2, "LLInt assumes that InitializationMode::NotInitialization is 0");
220     
221     STATIC_ASSERT(GetPutInfo::typeBits == 0x3ff);
222     STATIC_ASSERT(GetPutInfo::initializationShift == 10);
223     STATIC_ASSERT(GetPutInfo::initializationBits == 0xffc00);
224
225     STATIC_ASSERT(MarkedBlock::blockSize == 16 * 1024);
226     STATIC_ASSERT(blackThreshold == 0);
227
228     ASSERT(bitwise_cast<uintptr_t>(ShadowChicken::Packet::tailMarker()) == static_cast<uintptr_t>(0x7a11));
229
230     // FIXME: make these assertions less horrible.
231 #if !ASSERT_DISABLED
232     Vector<int> testVector;
233     testVector.resize(42);
234     ASSERT(bitwise_cast<uint32_t*>(&testVector)[sizeof(void*)/sizeof(uint32_t) + 1] == 42);
235     ASSERT(bitwise_cast<int**>(&testVector)[0] == testVector.begin());
236 #endif
237
238     ASSERT(StringImpl::s_hashFlag8BitBuffer == 8);
239
240     {
241         uint32_t bits = 0x120000;
242         UNUSED_PARAM(bits);
243         ArithProfile arithProfile;
244         arithProfile.lhsSawInt32();
245         arithProfile.rhsSawInt32();
246         ASSERT(arithProfile.bits() == bits);
247         ASSERT(ArithProfile::fromInt(bits).lhsObservedType().isOnlyInt32());
248         ASSERT(ArithProfile::fromInt(bits).rhsObservedType().isOnlyInt32());
249     }
250     {
251         uint32_t bits = 0x220000;
252         UNUSED_PARAM(bits);
253         ArithProfile arithProfile;
254         arithProfile.lhsSawNumber();
255         arithProfile.rhsSawInt32();
256         ASSERT(arithProfile.bits() == bits);
257         ASSERT(ArithProfile::fromInt(bits).lhsObservedType().isOnlyNumber());
258         ASSERT(ArithProfile::fromInt(bits).rhsObservedType().isOnlyInt32());
259     }
260     {
261         uint32_t bits = 0x240000;
262         UNUSED_PARAM(bits);
263         ArithProfile arithProfile;
264         arithProfile.lhsSawNumber();
265         arithProfile.rhsSawNumber();
266         ASSERT(arithProfile.bits() == bits);
267         ASSERT(ArithProfile::fromInt(bits).lhsObservedType().isOnlyNumber());
268         ASSERT(ArithProfile::fromInt(bits).rhsObservedType().isOnlyNumber());
269     }
270     {
271         uint32_t bits = 0x140000;
272         UNUSED_PARAM(bits);
273         ArithProfile arithProfile;
274         arithProfile.lhsSawInt32();
275         arithProfile.rhsSawNumber();
276         ASSERT(arithProfile.bits() == bits);
277         ASSERT(ArithProfile::fromInt(bits).lhsObservedType().isOnlyInt32());
278         ASSERT(ArithProfile::fromInt(bits).rhsObservedType().isOnlyNumber());
279     }
280 }
281 #if COMPILER(CLANG)
282 #pragma clang diagnostic pop
283 #endif
284
285 void Data::finalizeStats()
286 {
287 #if ENABLE(LLINT_STATS)
288     if (!Options::reportLLIntStats())
289         return;
290     
291     if (Options::llintStatsFile())
292         saveStats();
293     
294     dumpStats();
295 #endif
296 }
297
298 #if ENABLE(LLINT_STATS)
299 static const bool verboseStats = false;
300
301 static bool compareStats(const OpcodeStats& a, const OpcodeStats& b)
302 {
303     if (a.count > b.count)
304         return true;
305     if (a.count < b.count)
306         return false;
307     return a.slowPathCount > b.slowPathCount;
308 }
309
310 void Data::dumpStats()
311 {
312     ASSERT(Options::reportLLIntStats());
313     auto statsCopy = *s_opcodeStatsArray;
314     std::sort(statsCopy.begin(), statsCopy.end(), compareStats);
315
316     dataLog("Opcode stats:\n");
317     unsigned i = 0;
318     for (auto& stats : statsCopy) {
319         if (stats.count || stats.slowPathCount)
320             dataLog("   [", i++, "]: fast:", stats.count, " slow:", stats.slowPathCount, " ", opcodeNames[stats.id], "\n");
321     }
322 }
323
324 void Data::ensureStats()
325 {
326     static std::once_flag initializeOptionsOnceFlag;
327     std::call_once(initializeOptionsOnceFlag, [] {
328         s_opcodeStatsArray = new OpcodeStatsArray();
329         resetStats();
330     });
331 }
332
333 void Data::loadStats()
334 {
335     static NeverDestroyed<std::string> installedStatsFile;
336     if (!Options::llintStatsFile() || !installedStatsFile.get().compare(Options::llintStatsFile()))
337         return;
338
339     Options::reportLLIntStats() = true; // Force stats collection.
340     installedStatsFile.get() = Options::llintStatsFile();
341
342     ensureStats();
343
344     const char* filename = Options::llintStatsFile();
345     FILE* file = fopen(filename, "r");
346     if (!file) {
347         dataLogF("Failed to open file %s. Did you add the file-read-write-data entitlement to WebProcess.sb?\n", filename);
348         return;
349     }
350
351     resetStats();
352
353     OpcodeStats loaded;
354     unsigned index;
355     char opcodeName[100];
356     while (fscanf(file, "[%u]: fast:%zu slow:%zu id:%u %s\n", &index, &loaded.count, &loaded.slowPathCount, &loaded.id, opcodeName) != EOF) {
357         if (verboseStats)
358             dataLogF("loaded [%u]: fast %zu slow %zu id:%u %s\n", index, loaded.count, loaded.slowPathCount, loaded.id, opcodeName);
359
360         OpcodeStats& stats = opcodeStats(loaded.id);
361         stats.count = loaded.count;
362         stats.slowPathCount = loaded.slowPathCount;
363     }
364
365     if (verboseStats) {
366         dataLogF("After loading from %s, ", filename);
367         dumpStats();
368     }
369
370     int result = fclose(file);
371     if (result)
372         dataLogF("Failed to close file %s: %s\n", filename, strerror(errno));
373 }
374
375 void Data::resetStats()
376 {
377     unsigned i = 0;
378     for (auto& stats : *s_opcodeStatsArray) {
379         stats.id = static_cast<OpcodeID>(i++);
380         stats.count = 0;
381         stats.slowPathCount = 0;
382     }
383 }
384
385 void Data::saveStats()
386 {
387     ASSERT(Options::reportLLIntStats() && Options::llintStatsFile());
388     const char* filename = Options::llintStatsFile();
389
390     FILE* file = fopen(filename, "w");
391     if (!file) {
392         dataLogF("Failed to open file %s. Did you add the file-read-write-data entitlement to WebProcess.sb?\n", filename);
393         return;
394     }
395
396     auto statsCopy = *s_opcodeStatsArray;
397     std::sort(statsCopy.begin(), statsCopy.end(), compareStats);
398
399     int index = 0;
400     for (auto& stats : statsCopy) {
401         if (!stats.count && !stats.slowPathCount)
402             break; // stats are sorted. If we encountered 0 counts, then there are no more non-zero counts.
403
404         if (verboseStats)
405             dataLogF("saved [%u]: fast:%zu slow:%zu id:%u %s\n", index, stats.count, stats.slowPathCount, stats.id, opcodeNames[stats.id]);
406
407         fprintf(file, "[%u]: fast:%zu slow:%zu id:%u %s\n", index, stats.count, stats.slowPathCount, stats.id, opcodeNames[stats.id]);
408         index++;
409     }
410
411     int result = fclose(file);
412     if (result)
413         dataLogF("Failed to close file %s: %s\n", filename, strerror(errno));
414 }
415 #endif
416
417 } } // namespace JSC::LLInt