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