Air::handleCalleeSaves shouldn't save/restore the frame pointer
[WebKit-https.git] / Source / JavaScriptCore / b3 / air / AirHandleCalleeSaves.cpp
1 /*
2  * Copyright (C) 2015 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 "AirHandleCalleeSaves.h"
28
29 #if ENABLE(B3_JIT)
30
31 #include "AirCode.h"
32 #include "AirInsertionSet.h"
33 #include "AirPhaseScope.h"
34
35 namespace JSC { namespace B3 { namespace Air {
36
37 void handleCalleeSaves(Code& code)
38 {
39     PhaseScope phaseScope(code, "handleCalleeSaves");
40
41     RegisterSet usedCalleeSaves;
42
43     for (BasicBlock* block : code) {
44         for (Inst& inst : *block) {
45             inst.forEachTmpFast(
46                 [&] (Tmp& tmp) {
47                     // At first we just record all used regs.
48                     usedCalleeSaves.set(tmp.reg());
49                 });
50         }
51     }
52
53     // Now we filter to really get the callee saves.
54     usedCalleeSaves.filter(RegisterSet::calleeSaveRegisters());
55     usedCalleeSaves.exclude(RegisterSet::stackRegisters()); // We don't need to save FP here.
56
57     if (!usedCalleeSaves.numberOfSetRegisters())
58         return;
59
60     code.calleeSaveRegisters() = RegisterAtOffsetList(usedCalleeSaves);
61
62     size_t byteSize = 0;
63     for (const RegisterAtOffset& entry : code.calleeSaveRegisters())
64         byteSize = std::max(static_cast<size_t>(-entry.offset()), byteSize);
65
66     StackSlot* savesArea = code.addStackSlot(byteSize, StackSlotKind::Locked);
67     // This is a bit weird since we could have already pinned a different stack slot to this
68     // area. Also, our runtime does not require us to pin the saves area. Maybe we shouldn't pin it?
69     savesArea->setOffsetFromFP(-byteSize);
70
71     auto argFor = [&] (const RegisterAtOffset& entry) -> Arg {
72         return Arg::stack(savesArea, entry.offset() + byteSize);
73     };
74
75     InsertionSet insertionSet(code);
76     
77     // First insert saving code in the prologue.
78     for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
79         insertionSet.insert(
80             0, entry.reg().isGPR() ? Move : MoveDouble, code[0]->at(0).origin,
81             Tmp(entry.reg()), argFor(entry));
82     }
83     insertionSet.execute(code[0]);
84
85     // Now insert restore code at epilogues.
86     for (BasicBlock* block : code) {
87         Inst& last = block->last();
88         if (last.opcode != Ret)
89             continue;
90
91         for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
92             insertionSet.insert(
93                 block->size() - 1, entry.reg().isGPR() ? Move : MoveDouble, last.origin,
94                 argFor(entry), Tmp(entry.reg()));
95         }
96         insertionSet.execute(block);
97     }
98 }
99
100 } } } // namespace JSC::B3::Air
101
102 #endif // ENABLE(B3_JIT)