Unreviewed, rolling out r206314, r206316, and r206319.
[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) || CPU(SH4)
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 == 20);
160     STATIC_ASSERT(FinalObjectType == 21);
161     STATIC_ASSERT(JSFunctionType == 23);
162     STATIC_ASSERT(ArrayType == 31);
163     STATIC_ASSERT(DerivedArrayType == 32);
164     STATIC_ASSERT(ProxyObjectType == 116);
165     STATIC_ASSERT(Int8ArrayType == 100);
166     STATIC_ASSERT(Int16ArrayType == 101);
167     STATIC_ASSERT(Int32ArrayType == 102);
168     STATIC_ASSERT(Uint8ArrayType == 103);
169     STATIC_ASSERT(Uint8ClampedArrayType == 104);
170     STATIC_ASSERT(Uint16ArrayType == 105);
171     STATIC_ASSERT(Uint32ArrayType == 106);
172     STATIC_ASSERT(Float32ArrayType == 107);
173     STATIC_ASSERT(Float64ArrayType == 108);
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     ASSERT(!(reinterpret_cast<ptrdiff_t>((reinterpret_cast<WriteBarrier<JSCell>*>(0x4000)->slot())) - 0x4000));
183     static_assert(PutByIdPrimaryTypeMask == 0x6, "LLInt assumes PutByIdPrimaryTypeMask is == 0x6");
184     static_assert(PutByIdPrimaryTypeSecondary == 0x0, "LLInt assumes PutByIdPrimaryTypeSecondary is == 0x0");
185     static_assert(PutByIdPrimaryTypeObjectWithStructure == 0x2, "LLInt assumes PutByIdPrimaryTypeObjectWithStructure is == 0x2");
186     static_assert(PutByIdPrimaryTypeObjectWithStructureOrOther == 0x4, "LLInt assumes PutByIdPrimaryTypeObjectWithStructureOrOther is == 0x4");
187     static_assert(PutByIdSecondaryTypeMask == -0x8, "LLInt assumes PutByIdSecondaryTypeMask is == -0x8");
188     static_assert(PutByIdSecondaryTypeBottom == 0x0, "LLInt assumes PutByIdSecondaryTypeBottom is == 0x0");
189     static_assert(PutByIdSecondaryTypeBoolean == 0x8, "LLInt assumes PutByIdSecondaryTypeBoolean is == 0x8");
190     static_assert(PutByIdSecondaryTypeOther == 0x10, "LLInt assumes PutByIdSecondaryTypeOther is == 0x10");
191     static_assert(PutByIdSecondaryTypeInt32 == 0x18, "LLInt assumes PutByIdSecondaryTypeInt32 is == 0x18");
192     static_assert(PutByIdSecondaryTypeNumber == 0x20, "LLInt assumes PutByIdSecondaryTypeNumber is == 0x20");
193     static_assert(PutByIdSecondaryTypeString == 0x28, "LLInt assumes PutByIdSecondaryTypeString is == 0x28");
194     static_assert(PutByIdSecondaryTypeSymbol == 0x30, "LLInt assumes PutByIdSecondaryTypeSymbol is == 0x30");
195     static_assert(PutByIdSecondaryTypeObject == 0x38, "LLInt assumes PutByIdSecondaryTypeObject is == 0x38");
196     static_assert(PutByIdSecondaryTypeObjectOrOther == 0x40, "LLInt assumes PutByIdSecondaryTypeObjectOrOther is == 0x40");
197     static_assert(PutByIdSecondaryTypeTop == 0x48, "LLInt assumes PutByIdSecondaryTypeTop is == 0x48");
198
199     static_assert(GlobalProperty == 0, "LLInt assumes GlobalProperty ResultType is == 0");
200     static_assert(GlobalVar == 1, "LLInt assumes GlobalVar ResultType is == 1");
201     static_assert(GlobalLexicalVar == 2, "LLInt assumes GlobalLexicalVar ResultType is == 2");
202     static_assert(ClosureVar == 3, "LLInt assumes ClosureVar ResultType is == 3");
203     static_assert(LocalClosureVar == 4, "LLInt assumes LocalClosureVar ResultType is == 4");
204     static_assert(ModuleVar == 5, "LLInt assumes ModuleVar ResultType is == 5");
205     static_assert(GlobalPropertyWithVarInjectionChecks == 6, "LLInt assumes GlobalPropertyWithVarInjectionChecks ResultType is == 6");
206     static_assert(GlobalVarWithVarInjectionChecks == 7, "LLInt assumes GlobalVarWithVarInjectionChecks ResultType is == 7");
207     static_assert(GlobalLexicalVarWithVarInjectionChecks == 8, "LLInt assumes GlobalLexicalVarWithVarInjectionChecks ResultType is == 8");
208     static_assert(ClosureVarWithVarInjectionChecks == 9, "LLInt assumes ClosureVarWithVarInjectionChecks ResultType is == 9");
209
210     static_assert(static_cast<unsigned>(InitializationMode::NotInitialization) == 2, "LLInt assumes that InitializationMode::NotInitialization is 0");
211     
212     STATIC_ASSERT(GetPutInfo::typeBits == 0x3ff);
213     STATIC_ASSERT(GetPutInfo::initializationShift == 10);
214     STATIC_ASSERT(GetPutInfo::initializationBits == 0xffc00);
215
216     STATIC_ASSERT(MarkedBlock::blockSize == 16 * 1024);
217
218     ASSERT(bitwise_cast<uintptr_t>(ShadowChicken::Packet::tailMarker()) == static_cast<uintptr_t>(0x7a11));
219
220     // FIXME: make these assertions less horrible.
221 #if !ASSERT_DISABLED
222     Vector<int> testVector;
223     testVector.resize(42);
224     ASSERT(bitwise_cast<uint32_t*>(&testVector)[sizeof(void*)/sizeof(uint32_t) + 1] == 42);
225     ASSERT(bitwise_cast<int**>(&testVector)[0] == testVector.begin());
226 #endif
227
228     ASSERT(StringImpl::s_hashFlag8BitBuffer == 8);
229
230     {
231         uint32_t bits = 0x120000;
232         UNUSED_PARAM(bits);
233         ArithProfile arithProfile;
234         arithProfile.lhsSawInt32();
235         arithProfile.rhsSawInt32();
236         ASSERT(arithProfile.bits() == bits);
237         ASSERT(ArithProfile::fromInt(bits).lhsObservedType().isOnlyInt32());
238         ASSERT(ArithProfile::fromInt(bits).rhsObservedType().isOnlyInt32());
239     }
240     {
241         uint32_t bits = 0x220000;
242         UNUSED_PARAM(bits);
243         ArithProfile arithProfile;
244         arithProfile.lhsSawNumber();
245         arithProfile.rhsSawInt32();
246         ASSERT(arithProfile.bits() == bits);
247         ASSERT(ArithProfile::fromInt(bits).lhsObservedType().isOnlyNumber());
248         ASSERT(ArithProfile::fromInt(bits).rhsObservedType().isOnlyInt32());
249     }
250     {
251         uint32_t bits = 0x240000;
252         UNUSED_PARAM(bits);
253         ArithProfile arithProfile;
254         arithProfile.lhsSawNumber();
255         arithProfile.rhsSawNumber();
256         ASSERT(arithProfile.bits() == bits);
257         ASSERT(ArithProfile::fromInt(bits).lhsObservedType().isOnlyNumber());
258         ASSERT(ArithProfile::fromInt(bits).rhsObservedType().isOnlyNumber());
259     }
260     {
261         uint32_t bits = 0x140000;
262         UNUSED_PARAM(bits);
263         ArithProfile arithProfile;
264         arithProfile.lhsSawInt32();
265         arithProfile.rhsSawNumber();
266         ASSERT(arithProfile.bits() == bits);
267         ASSERT(ArithProfile::fromInt(bits).lhsObservedType().isOnlyInt32());
268         ASSERT(ArithProfile::fromInt(bits).rhsObservedType().isOnlyNumber());
269     }
270 }
271 #if COMPILER(CLANG)
272 #pragma clang diagnostic pop
273 #endif
274
275 void Data::finalizeStats()
276 {
277 #if ENABLE(LLINT_STATS)
278     if (!Options::reportLLIntStats())
279         return;
280     
281     if (Options::llintStatsFile())
282         saveStats();
283     
284     dumpStats();
285 #endif
286 }
287
288 #if ENABLE(LLINT_STATS)
289 static const bool verboseStats = false;
290
291 static bool compareStats(const OpcodeStats& a, const OpcodeStats& b)
292 {
293     if (a.count > b.count)
294         return true;
295     if (a.count < b.count)
296         return false;
297     return a.slowPathCount > b.slowPathCount;
298 }
299
300 void Data::dumpStats()
301 {
302     ASSERT(Options::reportLLIntStats());
303     auto statsCopy = *s_opcodeStatsArray;
304     std::sort(statsCopy.begin(), statsCopy.end(), compareStats);
305
306     dataLog("Opcode stats:\n");
307     unsigned i = 0;
308     for (auto& stats : statsCopy) {
309         if (stats.count || stats.slowPathCount)
310             dataLog("   [", i++, "]: fast:", stats.count, " slow:", stats.slowPathCount, " ", opcodeNames[stats.id], "\n");
311     }
312 }
313
314 void Data::ensureStats()
315 {
316     static std::once_flag initializeOptionsOnceFlag;
317     std::call_once(initializeOptionsOnceFlag, [] {
318         s_opcodeStatsArray = new OpcodeStatsArray();
319         resetStats();
320     });
321 }
322
323 void Data::loadStats()
324 {
325     static NeverDestroyed<std::string> installedStatsFile;
326     if (!Options::llintStatsFile() || !installedStatsFile.get().compare(Options::llintStatsFile()))
327         return;
328
329     Options::reportLLIntStats() = true; // Force stats collection.
330     installedStatsFile.get() = Options::llintStatsFile();
331
332     ensureStats();
333
334     const char* filename = Options::llintStatsFile();
335     FILE* file = fopen(filename, "r");
336     if (!file) {
337         dataLogF("Failed to open file %s. Did you add the file-read-write-data entitlement to WebProcess.sb?\n", filename);
338         return;
339     }
340
341     resetStats();
342
343     OpcodeStats loaded;
344     unsigned index;
345     char opcodeName[100];
346     while (fscanf(file, "[%u]: fast:%zu slow:%zu id:%u %s\n", &index, &loaded.count, &loaded.slowPathCount, &loaded.id, opcodeName) != EOF) {
347         if (verboseStats)
348             dataLogF("loaded [%u]: fast %zu slow %zu id:%u %s\n", index, loaded.count, loaded.slowPathCount, loaded.id, opcodeName);
349
350         OpcodeStats& stats = opcodeStats(loaded.id);
351         stats.count = loaded.count;
352         stats.slowPathCount = loaded.slowPathCount;
353     }
354
355     if (verboseStats) {
356         dataLogF("After loading from %s, ", filename);
357         dumpStats();
358     }
359
360     int result = fclose(file);
361     if (result)
362         dataLogF("Failed to close file %s: %s\n", filename, strerror(errno));
363 }
364
365 void Data::resetStats()
366 {
367     unsigned i = 0;
368     for (auto& stats : *s_opcodeStatsArray) {
369         stats.id = static_cast<OpcodeID>(i++);
370         stats.count = 0;
371         stats.slowPathCount = 0;
372     }
373 }
374
375 void Data::saveStats()
376 {
377     ASSERT(Options::reportLLIntStats() && Options::llintStatsFile());
378     const char* filename = Options::llintStatsFile();
379
380     FILE* file = fopen(filename, "w");
381     if (!file) {
382         dataLogF("Failed to open file %s. Did you add the file-read-write-data entitlement to WebProcess.sb?\n", filename);
383         return;
384     }
385
386     auto statsCopy = *s_opcodeStatsArray;
387     std::sort(statsCopy.begin(), statsCopy.end(), compareStats);
388
389     int index = 0;
390     for (auto& stats : statsCopy) {
391         if (!stats.count && !stats.slowPathCount)
392             break; // stats are sorted. If we encountered 0 counts, then there are no more non-zero counts.
393
394         if (verboseStats)
395             dataLogF("saved [%u]: fast:%zu slow:%zu id:%u %s\n", index, stats.count, stats.slowPathCount, stats.id, opcodeNames[stats.id]);
396
397         fprintf(file, "[%u]: fast:%zu slow:%zu id:%u %s\n", index, stats.count, stats.slowPathCount, stats.id, opcodeNames[stats.id]);
398         index++;
399     }
400
401     int result = fclose(file);
402     if (result)
403         dataLogF("Failed to close file %s: %s\n", filename, strerror(errno));
404 }
405 #endif
406
407 } } // namespace JSC::LLInt