Implement a faster Interpreter::getOpcodeID().
[WebKit-https.git] / Source / JavaScriptCore / llint / LowLevelInterpreter.cpp
1 /*
2  * Copyright (C) 2012-2017 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 "LowLevelInterpreter.h"
28
29 #include "LLIntOfflineAsmConfig.h"
30 #include <wtf/InlineASM.h>
31
32 #if !ENABLE(JIT)
33 #include "CLoopStackInlines.h"
34 #include "CodeBlock.h"
35 #include "CommonSlowPaths.h"
36 #include "Interpreter.h"
37 #include "LLIntCLoop.h"
38 #include "LLIntData.h"
39 #include "LLIntSlowPaths.h"
40 #include "JSCInlines.h"
41 #include <wtf/Assertions.h>
42 #include <wtf/MathExtras.h>
43
44 using namespace JSC::LLInt;
45
46 // LLInt C Loop opcodes
47 // ====================
48 // In the implementation of the C loop, the LLint trampoline glue functions
49 // (e.g. llint_program_prologue, llint_eval_prologue, etc) are addressed as
50 // if they are bytecode handlers. That means the names of the trampoline
51 // functions will be added to the OpcodeID list via the
52 // FOR_EACH_LLINT_OPCODE_EXTENSION() macro that FOR_EACH_OPCODE_ID()
53 // includes.
54 //
55 // In addition, some JIT trampoline functions which are needed by LLInt
56 // (e.g. getHostCallReturnValue, ctiOpThrowNotCaught) are also added as
57 // bytecodes, and the CLoop will provide bytecode handlers for them.
58 //
59 // In the CLoop, we can only dispatch indirectly to these bytecodes
60 // (including the LLInt and JIT extensions). All other dispatches
61 // (i.e. goto's) must be to a known label (i.e. local / global labels).
62
63
64 // How are the opcodes named?
65 // ==========================
66 // Here is a table to show examples of how each of the manifestation of the
67 // opcodes are named:
68 //
69 //   Type:                        Opcode            Trampoline Glue
70 //                                ======            ===============
71 //   [In the llint .asm files]
72 //   llint labels:                llint_op_enter    llint_program_prologue
73 //
74 //   OpcodeID:                    op_enter          llint_program
75 //                                [in Opcode.h]     [in LLIntOpcode.h]
76 //
77 //   When using a switch statement dispatch in the CLoop, each "opcode" is
78 //   a case statement:
79 //   Opcode:                      case op_enter:    case llint_program_prologue:
80 //
81 //   When using a computed goto dispatch in the CLoop, each opcode is a label:
82 //   Opcode:                      op_enter:         llint_program_prologue:
83
84
85 //============================================================================
86 // Define the opcode dispatch mechanism when using the C loop:
87 //
88
89 // These are for building a C Loop interpreter:
90 #define OFFLINE_ASM_BEGIN
91 #define OFFLINE_ASM_END
92
93 #if ENABLE(OPCODE_TRACING)
94 #define TRACE_OPCODE(opcode) dataLogF("   op %s\n", #opcode)
95 #else
96 #define TRACE_OPCODE(opcode)
97 #endif
98
99 // To keep compilers happy in case of unused labels, force usage of the label:
100 #define USE_LABEL(label) \
101     do { \
102         if (false) \
103             goto label; \
104     } while (false)
105
106 #define OFFLINE_ASM_OPCODE_LABEL(opcode) DEFINE_OPCODE(opcode) USE_LABEL(opcode); TRACE_OPCODE(opcode);
107
108 #define OFFLINE_ASM_GLOBAL_LABEL(label)  OFFLINE_ASM_GLUE_LABEL(label)
109
110 #if ENABLE(COMPUTED_GOTO_OPCODES)
111 #define OFFLINE_ASM_GLUE_LABEL(label)  label: USE_LABEL(label);
112 #else
113 #define OFFLINE_ASM_GLUE_LABEL(label)  case label: label: USE_LABEL(label);
114 #endif
115
116 #define OFFLINE_ASM_LOCAL_LABEL(label) label: USE_LABEL(label);
117
118
119 //============================================================================
120 // Some utilities:
121 //
122
123 namespace JSC {
124 namespace LLInt {
125
126 #if USE(JSVALUE32_64)
127 static double Ints2Double(uint32_t lo, uint32_t hi)
128 {
129     union {
130         double dval;
131         uint64_t ival64;
132     } u;
133     u.ival64 = (static_cast<uint64_t>(hi) << 32) | lo;
134     return u.dval;
135 }
136
137 static void Double2Ints(double val, uint32_t& lo, uint32_t& hi)
138 {
139     union {
140         double dval;
141         uint64_t ival64;
142     } u;
143     u.dval = val;
144     hi = static_cast<uint32_t>(u.ival64 >> 32);
145     lo = static_cast<uint32_t>(u.ival64);
146 }
147 #endif // USE(JSVALUE32_64)
148
149 } // namespace LLint
150
151
152 //============================================================================
153 // CLoopRegister is the storage for an emulated CPU register.
154 // It defines the policy of how ints smaller than intptr_t are packed into the
155 // pseudo register, as well as hides endianness differences.
156
157 struct CLoopRegister {
158     CLoopRegister() { i = static_cast<intptr_t>(0xbadbeef0baddbeef); }
159     union {
160         intptr_t i;
161         uintptr_t u;
162 #if USE(JSVALUE64)
163 #if CPU(BIG_ENDIAN)
164         struct {
165             int32_t i32padding;
166             int32_t i32;
167         };
168         struct {
169             uint32_t u32padding;
170             uint32_t u32;
171         };
172         struct {
173             int8_t i8padding[7];
174             int8_t i8;
175         };
176         struct {
177             uint8_t u8padding[7];
178             uint8_t u8;
179         };
180 #else // !CPU(BIG_ENDIAN)
181         struct {
182             int32_t i32;
183             int32_t i32padding;
184         };
185         struct {
186             uint32_t u32;
187             uint32_t u32padding;
188         };
189         struct {
190             int8_t i8;
191             int8_t i8padding[7];
192         };
193         struct {
194             uint8_t u8;
195             uint8_t u8padding[7];
196         };
197 #endif // !CPU(BIG_ENDIAN)
198 #else // !USE(JSVALUE64)
199         int32_t i32;
200         uint32_t u32;
201
202 #if CPU(BIG_ENDIAN)
203         struct {
204             int8_t i8padding[3];
205             int8_t i8;
206         };
207         struct {
208             uint8_t u8padding[3];
209             uint8_t u8;
210         };
211
212 #else // !CPU(BIG_ENDIAN)
213         struct {
214             int8_t i8;
215             int8_t i8padding[3];
216         };
217         struct {
218             uint8_t u8;
219             uint8_t u8padding[3];
220         };
221 #endif // !CPU(BIG_ENDIAN)
222 #endif // !USE(JSVALUE64)
223
224         intptr_t* ip;
225         int8_t* i8p;
226         void* vp;
227         CallFrame* callFrame;
228         ExecState* execState;
229         void* instruction;
230         VM* vm;
231         JSCell* cell;
232         ProtoCallFrame* protoCallFrame;
233         NativeFunction nativeFunc;
234 #if USE(JSVALUE64)
235         int64_t i64;
236         uint64_t u64;
237         EncodedJSValue encodedJSValue;
238         double castToDouble;
239 #endif
240         Opcode opcode;
241     };
242
243     operator ExecState*() { return execState; }
244     operator Instruction*() { return reinterpret_cast<Instruction*>(instruction); }
245     operator VM*() { return vm; }
246     operator ProtoCallFrame*() { return protoCallFrame; }
247     operator Register*() { return reinterpret_cast<Register*>(vp); }
248     operator JSCell*() { return cell; }
249
250 #if USE(JSVALUE64)
251     inline void clearHighWord() { i32padding = 0; }
252 #else
253     inline void clearHighWord() { }
254 #endif
255 };
256
257 //============================================================================
258 // The llint C++ interpreter loop:
259 //
260
261 JSValue CLoop::execute(OpcodeID entryOpcodeID, void* executableAddress, VM* vm, ProtoCallFrame* protoCallFrame, bool isInitializationPass)
262 {
263     #define CAST reinterpret_cast
264     #define SIGN_BIT32(x) ((x) & 0x80000000)
265
266     // One-time initialization of our address tables. We have to put this code
267     // here because our labels are only in scope inside this function. The
268     // caller (or one of its ancestors) is responsible for ensuring that this
269     // is only called once during the initialization of the VM before threads
270     // are at play.
271     if (UNLIKELY(isInitializationPass)) {
272 #if ENABLE(COMPUTED_GOTO_OPCODES)
273         Opcode* opcodeMap = LLInt::opcodeMap();
274         #define OPCODE_ENTRY(__opcode, length) \
275             opcodeMap[__opcode] = bitwise_cast<void*>(&&__opcode);
276         FOR_EACH_OPCODE_ID(OPCODE_ENTRY)
277         #undef OPCODE_ENTRY
278
279         #define LLINT_OPCODE_ENTRY(__opcode, length) \
280             opcodeMap[__opcode] = bitwise_cast<void*>(&&__opcode);
281
282         FOR_EACH_LLINT_NATIVE_HELPER(LLINT_OPCODE_ENTRY)
283         #undef LLINT_OPCODE_ENTRY
284 #endif
285         // Note: we can only set the exceptionInstructions after we have
286         // initialized the opcodeMap above. This is because getCodePtr()
287         // can depend on the opcodeMap.
288         Instruction* exceptionInstructions = LLInt::exceptionInstructions();
289         for (int i = 0; i < maxOpcodeLength + 1; ++i)
290             exceptionInstructions[i].u.pointer =
291                 LLInt::getCodePtr(llint_throw_from_slow_path_trampoline);
292
293         return JSValue();
294     }
295
296     // Define the pseudo registers used by the LLINT C Loop backend:
297     ASSERT(sizeof(CLoopRegister) == sizeof(intptr_t));
298
299     union CLoopDoubleRegister {
300         double d;
301 #if USE(JSVALUE64)
302         int64_t castToInt64;
303 #endif
304     };
305
306     // The CLoop llint backend is initially based on the ARMv7 backend, and
307     // then further enhanced with a few instructions from the x86 backend to
308     // support building for X64 targets. Hence, the shape of the generated
309     // code and the usage convention of registers will look a lot like the
310     // ARMv7 backend's.
311     //
312     // For example, on a 32-bit build:
313     // 1. Outgoing args will be set up as follows:
314     //    arg1 in t0 (r0 on ARM)
315     //    arg2 in t1 (r1 on ARM)
316     // 2. 32 bit return values will be in t0 (r0 on ARM).
317     // 3. 64 bit return values (e.g. doubles) will be in t0,t1 (r0,r1 on ARM).
318     //
319     // But instead of naming these simulator registers based on their ARM
320     // counterparts, we'll name them based on their original llint asm names.
321     // This will make it easier to correlate the generated code with the
322     // original llint asm code.
323     //
324     // On a 64-bit build, it more like x64 in that the registers are 64 bit.
325     // Hence:
326     // 1. Outgoing args are still the same: arg1 in t0, arg2 in t1, etc.
327     // 2. 32 bit result values will be in the low 32-bit of t0.
328     // 3. 64 bit result values will be in t0.
329
330     CLoopRegister t0, t1, t2, t3, t5, t7, sp, cfr, lr, pc;
331 #if USE(JSVALUE64)
332     CLoopRegister pcBase, tagTypeNumber, tagMask;
333 #endif
334     CLoopDoubleRegister d0, d1;
335
336     lr.opcode = getOpcode(llint_return_to_host);
337     sp.vp = vm->interpreter->cloopStack().topOfStack() + 1;
338     cfr.callFrame = vm->topCallFrame;
339 #ifndef NDEBUG
340     void* startSP = sp.vp;
341     CallFrame* startCFR = cfr.callFrame;
342 #endif
343
344     // Initialize the incoming args for doVMEntryToJavaScript:
345     t0.vp = executableAddress;
346     t1.vm = vm;
347     t2.protoCallFrame = protoCallFrame;
348
349 #if USE(JSVALUE64)
350     // For the ASM llint, JITStubs takes care of this initialization. We do
351     // it explicitly here for the C loop:
352     tagTypeNumber.i = 0xFFFF000000000000;
353     tagMask.i = 0xFFFF000000000002;
354 #endif // USE(JSVALUE64)
355
356     // Interpreter variables for value passing between opcodes and/or helpers:
357     NativeFunction nativeFunc = 0;
358     JSValue functionReturnValue;
359     Opcode opcode = getOpcode(entryOpcodeID);
360
361 #define PUSH(cloopReg) \
362     do { \
363         sp.ip--; \
364         *sp.ip = cloopReg.i; \
365     } while (false)
366
367 #define POP(cloopReg) \
368     do { \
369         cloopReg.i = *sp.ip; \
370         sp.ip++; \
371     } while (false)
372
373 #if ENABLE(OPCODE_STATS)
374 #define RECORD_OPCODE_STATS(__opcode) OpcodeStats::recordInstruction(__opcode)
375 #else
376 #define RECORD_OPCODE_STATS(__opcode)
377 #endif
378
379 #if USE(JSVALUE32_64)
380 #define FETCH_OPCODE() pc.opcode
381 #else // USE(JSVALUE64)
382 #define FETCH_OPCODE() *bitwise_cast<Opcode*>(pcBase.i8p + pc.i * 8)
383 #endif // USE(JSVALUE64)
384
385 #define NEXT_INSTRUCTION() \
386     do {                         \
387         opcode = FETCH_OPCODE(); \
388         DISPATCH_OPCODE();       \
389     } while (false)
390
391 #if ENABLE(COMPUTED_GOTO_OPCODES)
392
393     //========================================================================
394     // Loop dispatch mechanism using computed goto statements:
395
396     #define DISPATCH_OPCODE() goto *opcode
397
398     #define DEFINE_OPCODE(__opcode) \
399         __opcode: \
400             RECORD_OPCODE_STATS(__opcode);
401
402     // Dispatch to the current PC's bytecode:
403     DISPATCH_OPCODE();
404
405 #else // !ENABLE(COMPUTED_GOTO_OPCODES)
406     //========================================================================
407     // Loop dispatch mechanism using a C switch statement:
408
409     #define DISPATCH_OPCODE() goto dispatchOpcode
410
411     #define DEFINE_OPCODE(__opcode) \
412         case __opcode: \
413         __opcode: \
414             RECORD_OPCODE_STATS(__opcode);
415
416     // Dispatch to the current PC's bytecode:
417     dispatchOpcode:
418     switch (opcode)
419
420 #endif // !ENABLE(COMPUTED_GOTO_OPCODES)
421
422     //========================================================================
423     // Bytecode handlers:
424     {
425         // This is the file generated by offlineasm, which contains all of the
426         // bytecode handlers for the interpreter, as compiled from
427         // LowLevelInterpreter.asm and its peers.
428
429         #include "LLIntAssembly.h"
430
431         OFFLINE_ASM_GLUE_LABEL(llint_return_to_host)
432         {
433             ASSERT(startSP == sp.vp);
434             ASSERT(startCFR == cfr.callFrame);
435 #if USE(JSVALUE32_64)
436             return JSValue(t1.i, t0.i); // returning JSValue(tag, payload);
437 #else
438             return JSValue::decode(t0.encodedJSValue);
439 #endif
440         }
441
442         // In the ASM llint, getHostCallReturnValue() is a piece of glue
443         // function provided by the JIT (see jit/JITOperations.cpp).
444         // We simulate it here with a pseduo-opcode handler.
445         OFFLINE_ASM_GLUE_LABEL(getHostCallReturnValue)
446         {
447             // The part in getHostCallReturnValueWithExecState():
448             JSValue result = vm->hostCallReturnValue;
449 #if USE(JSVALUE32_64)
450             t1.i = result.tag();
451             t0.i = result.payload();
452 #else
453             t0.encodedJSValue = JSValue::encode(result);
454 #endif
455             opcode = lr.opcode;
456             DISPATCH_OPCODE();
457         }
458
459 #if !ENABLE(COMPUTED_GOTO_OPCODES)
460     default:
461         ASSERT(false);
462 #endif
463
464     } // END bytecode handler cases.
465
466 #if ENABLE(COMPUTED_GOTO_OPCODES)
467     // Keep the compiler happy so that it doesn't complain about unused
468     // labels for the LLInt trampoline glue. The labels are automatically
469     // emitted by label macros above, and some of them are referenced by
470     // the llint generated code. Since we can't tell ahead of time which
471     // will be referenced and which will be not, we'll just passify the
472     // compiler on all such labels:
473     #define LLINT_OPCODE_ENTRY(__opcode, length) \
474         UNUSED_LABEL(__opcode);
475         FOR_EACH_OPCODE_ID(LLINT_OPCODE_ENTRY);
476     #undef LLINT_OPCODE_ENTRY
477 #endif
478
479     #undef NEXT_INSTRUCTION
480     #undef DEFINE_OPCODE
481     #undef CHECK_FOR_TIMEOUT
482     #undef CAST
483     #undef SIGN_BIT32
484
485     return JSValue(); // to suppress a compiler warning.
486 } // Interpreter::llintCLoopExecute()
487
488 } // namespace JSC
489
490 #elif !COMPILER(MSVC)
491
492 //============================================================================
493 // Define the opcode dispatch mechanism when using an ASM loop:
494 //
495
496 // These are for building an interpreter from generated assembly code:
497 #define OFFLINE_ASM_BEGIN   asm (
498 #define OFFLINE_ASM_END     );
499
500 #if USE(LLINT_EMBEDDED_OPCODE_ID)
501 #define EMBED_OPCODE_ID_IF_NEEDED(__opcode) ".int " __opcode##_value_string "\n"
502 #else
503 #define EMBED_OPCODE_ID_IF_NEEDED(__opcode)
504 #endif
505
506 #define OFFLINE_ASM_OPCODE_LABEL(__opcode) \
507     EMBED_OPCODE_ID_IF_NEEDED(__opcode) \
508     OFFLINE_ASM_LOCAL_LABEL(llint_##__opcode)
509
510 #define OFFLINE_ASM_GLUE_LABEL(__opcode)   OFFLINE_ASM_LOCAL_LABEL(__opcode)
511
512 #if CPU(ARM_THUMB2)
513 #define OFFLINE_ASM_GLOBAL_LABEL(label)          \
514     ".text\n"                                    \
515     ".align 4\n"                                 \
516     ".globl " SYMBOL_STRING(label) "\n"          \
517     HIDE_SYMBOL(label) "\n"                      \
518     ".thumb\n"                                   \
519     ".thumb_func " THUMB_FUNC_PARAM(label) "\n"  \
520     SYMBOL_STRING(label) ":\n"
521 #elif CPU(ARM64)
522 #define OFFLINE_ASM_GLOBAL_LABEL(label)         \
523     ".text\n"                                   \
524     ".align 4\n"                                \
525     ".globl " SYMBOL_STRING(label) "\n"         \
526     HIDE_SYMBOL(label) "\n"                     \
527     SYMBOL_STRING(label) ":\n"
528 #else
529 #define OFFLINE_ASM_GLOBAL_LABEL(label)         \
530     ".text\n"                                   \
531     ".globl " SYMBOL_STRING(label) "\n"         \
532     HIDE_SYMBOL(label) "\n"                     \
533     SYMBOL_STRING(label) ":\n"
534 #endif
535
536 #define OFFLINE_ASM_LOCAL_LABEL(label)   LOCAL_LABEL_STRING(label) ":\n"
537
538 // This is a file generated by offlineasm, which contains all of the assembly code
539 // for the interpreter, as compiled from LowLevelInterpreter.asm.
540 #include "LLIntAssembly.h"
541
542 #endif // ENABLE(JIT)