LCOV - code coverage report
Current view: directory - js/src/methodjit - StubCompiler.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 97 96 99.0 %
Date: 2012-06-02 Functions: 15 15 100.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=99:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
      18                 :  * May 28, 2008.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  *   Brendan Eich <brendan@mozilla.org>
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   David Anderson <danderson@mozilla.com>
      25                 :  *   David Mandelin <dmandelin@mozilla.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "StubCalls.h"
      42                 : #include "StubCompiler.h"
      43                 : #include "Compiler.h"
      44                 : #include "assembler/assembler/LinkBuffer.h"
      45                 : #include "FrameState-inl.h"
      46                 : 
      47                 : using namespace js;
      48                 : using namespace mjit;
      49                 : 
      50          134091 : StubCompiler::StubCompiler(JSContext *cx, mjit::Compiler &cc, FrameState &frame)
      51                 : : cx(cx),
      52                 :   cc(cc),
      53                 :   frame(frame),
      54                 :   generation(1),
      55                 :   lastGeneration(0),
      56                 :   exits(CompilerAllocPolicy(cx, cc)),
      57                 :   joins(CompilerAllocPolicy(cx, cc)),
      58                 :   scriptJoins(CompilerAllocPolicy(cx, cc)),
      59          134091 :   jumpList(SystemAllocPolicy())
      60                 : {
      61                 : #ifdef DEBUG
      62          134091 :     masm.setSpewPath(true);
      63                 : #endif
      64          134091 : }
      65                 : 
      66                 : void
      67         4975357 : StubCompiler::linkExitDirect(Jump j, Label L)
      68                 : {
      69         4975357 :     exits.append(CrossPatch(j, L));
      70         4975357 : }
      71                 : 
      72                 : JSC::MacroAssembler::Label
      73         3062839 : StubCompiler::syncExit(Uses uses)
      74                 : {
      75         3062839 :     JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW MERGE CODE ---- \n");
      76                 : 
      77         3062839 :     if (lastGeneration == generation) {
      78          461515 :         Jump j2 = masm.jump();
      79          461515 :         jumpList.append(j2);
      80                 :     }
      81                 : 
      82         3062839 :     Label l = masm.label();
      83         3062839 :     frame.sync(masm, uses);
      84         3062839 :     lastGeneration = generation;
      85                 : 
      86         3062839 :     JaegerSpew(JSpew_Insns, " ---- END SLOW MERGE CODE ---- \n");
      87                 :     
      88                 :     return l;
      89                 : }
      90                 : 
      91                 : JSC::MacroAssembler::Label
      92          621731 : StubCompiler::syncExitAndJump(Uses uses)
      93                 : {
      94          621731 :     Label l = syncExit(uses);
      95          621731 :     Jump j2 = masm.jump();
      96          621731 :     jumpList.append(j2);
      97                 :     /* Suppress jumping on next sync/link. */
      98          621731 :     generation++;
      99                 :     return l;
     100                 : }
     101                 : 
     102                 : // Link an exit from the fast path to a slow path. This does two main things:
     103                 : // (a) links the given jump to the slow path, and (b) generates a prolog for
     104                 : // the slow path that syncs frame state for a slow call that uses |uses|
     105                 : // values from the top of the stack.
     106                 : //
     107                 : // The return value is the label for the start of the merge code. This is
     108                 : // the correct place to jump to in order to execute the slow path being
     109                 : // generated here.
     110                 : //
     111                 : // Note 1: Slow path generation is interleaved with fast path generation, but
     112                 : // the slow path goes into a separate buffer. The slow path code is appended
     113                 : // to the fast path code to keep it nearby in code memory.
     114                 : //
     115                 : // Note 2: A jump from the fast path to the slow path is called an "exit".
     116                 : //         A jump from the slow path to the fast path is called a "rejoin".
     117                 : JSC::MacroAssembler::Label
     118         2151857 : StubCompiler::linkExit(Jump j, Uses uses)
     119                 : {
     120         2151857 :     Label l = syncExit(uses);
     121         2151857 :     linkExitDirect(j, l);
     122                 :     return l;
     123                 : }
     124                 : 
     125                 : // Special version of linkExit that is used when there is a JavaScript
     126                 : // control-flow branch after the slow path. Our compilation strategy
     127                 : // requires the JS frame to be fully materialized in memory across branches.
     128                 : // This function does a linkExit and also fully materializes the frame.
     129                 : void
     130           79027 : StubCompiler::linkExitForBranch(Jump j)
     131                 : {
     132           79027 :     Label l = syncExit(Uses(frame.frameSlots()));
     133           79027 :     linkExitDirect(j, l);
     134           79027 : }
     135                 : 
     136                 : void
     137         2671320 : StubCompiler::leave()
     138                 : {
     139         2671320 :     JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW LEAVE CODE ---- \n");
     140         3754566 :     for (size_t i = 0; i < jumpList.length(); i++)
     141         1083246 :         jumpList[i].linkTo(masm.label(), &masm);
     142         2671320 :     jumpList.clear();
     143         2671320 :     generation++;
     144         2671320 :     JaegerSpew(JSpew_Insns, " ---- END SLOW LEAVE CODE ---- \n");
     145         2671320 : }
     146                 :  
     147                 : void
     148         3017272 : StubCompiler::rejoin(Changes changes)
     149                 : {
     150         3017272 :     JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW RESTORE CODE ---- \n");
     151                 : 
     152         3017272 :     frame.merge(masm, changes);
     153                 : 
     154         3017272 :     unsigned index = crossJump(masm.jump(), cc.getLabel());
     155         3017272 :     if (cc.loop)
     156          365808 :         cc.loop->addJoin(index, false);
     157                 : 
     158         3017272 :     JaegerSpew(JSpew_Insns, " ---- END SLOW RESTORE CODE ---- \n");
     159         3017272 : }
     160                 : 
     161                 : void
     162          564349 : StubCompiler::linkRejoin(Jump j)
     163                 : {
     164          564349 :     crossJump(j, cc.getLabel());
     165          564349 : }
     166                 : 
     167                 : typedef JSC::MacroAssembler::RegisterID RegisterID;
     168                 : typedef JSC::MacroAssembler::ImmPtr ImmPtr;
     169                 : typedef JSC::MacroAssembler::Imm32 Imm32;
     170                 : typedef JSC::MacroAssembler::DataLabelPtr DataLabelPtr;
     171                 : 
     172                 : JSC::MacroAssembler::Call
     173         3503238 : StubCompiler::emitStubCall(void *ptr, RejoinState rejoin, Uses uses)
     174                 : {
     175         3503238 :     return emitStubCall(ptr, rejoin, uses, frame.totalDepth());
     176                 : }
     177                 : 
     178                 : JSC::MacroAssembler::Call
     179         3666774 : StubCompiler::emitStubCall(void *ptr, RejoinState rejoin, Uses uses, int32_t slots)
     180                 : {
     181         3666774 :     JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW CALL CODE ---- \n");
     182         3666774 :     masm.bumpStubCounter(cc.script, cc.PC, Registers::tempCallReg());
     183         3666774 :     DataLabelPtr inlinePatch;
     184         3666774 :     Call cl = masm.fallibleVMCall(cx->typeInferenceEnabled(),
     185         7333548 :                                   ptr, cc.outerPC(), &inlinePatch, slots);
     186         3666774 :     JaegerSpew(JSpew_Insns, " ---- END SLOW CALL CODE ---- \n");
     187                 : 
     188                 :     /* Add the call site for debugging and recompilation. */
     189                 :     Compiler::InternalCallSite site(masm.callReturnOffset(cl),
     190                 :                                     cc.inlineIndex(), cc.inlinePC(),
     191         3666774 :                                     rejoin, true);
     192         3666774 :     site.inlinePatch = inlinePatch;
     193                 : 
     194                 :     /* Add a hook for restoring loop invariants if necessary. */
     195         3666774 :     if (cc.loop && cc.loop->generatingInvariants()) {
     196           30100 :         site.loopJumpLabel = masm.label();
     197           30100 :         Jump j = masm.jump();
     198           30100 :         Label l = masm.label();
     199                 :         /* MissedBoundsCheck* are not actually called, so f.regs need to be written before InvariantFailure. */
     200                 :         bool entry = (ptr == JS_FUNC_TO_DATA_PTR(void *, stubs::MissedBoundsCheckEntry))
     201           30100 :                   || (ptr == JS_FUNC_TO_DATA_PTR(void *, stubs::MissedBoundsCheckHead));
     202           30100 :         cc.loop->addInvariantCall(j, l, true, entry, cc.callSites.length(), uses);
     203                 :     }
     204                 : 
     205         3666774 :     cc.addCallSite(site);
     206                 :     return cl;
     207                 : }
     208                 : 
     209                 : void
     210          128827 : StubCompiler::fixCrossJumps(uint8_t *ncode, size_t offset, size_t total)
     211                 : {
     212          257654 :     JSC::LinkBuffer fast(ncode, total, JSC::METHOD_CODE);
     213          257654 :     JSC::LinkBuffer slow(ncode + offset, total - offset, JSC::METHOD_CODE);
     214                 : 
     215         5103866 :     for (size_t i = 0; i < exits.length(); i++)
     216         4975039 :         fast.link(exits[i].from, slow.locationOf(exits[i].to));
     217                 : 
     218          270499 :     for (size_t i = 0; i < scriptJoins.length(); i++) {
     219          141672 :         const CrossJumpInScript &cj = scriptJoins[i];
     220          141672 :         slow.link(cj.from, fast.locationOf(cc.labelOf(cj.pc, cj.inlineIndex)));
     221                 :     }
     222                 : 
     223         4282235 :     for (size_t i = 0; i < joins.length(); i++)
     224         4153408 :         slow.link(joins[i].from, fast.locationOf(joins[i].to));
     225          128827 : }
     226                 : 
     227                 : unsigned
     228         4153780 : StubCompiler::crossJump(Jump j, Label L)
     229                 : {
     230         4153780 :     joins.append(CrossPatch(j, L));
     231                 : 
     232                 :     /* This won't underflow, as joins has space preallocated for some entries. */
     233         4153780 :     return joins.length() - 1;
     234                 : }
     235                 : 
     236                 : bool
     237          204028 : StubCompiler::jumpInScript(Jump j, jsbytecode *target)
     238                 : {
     239          204028 :     if (cc.knownJump(target)) {
     240           62334 :         unsigned index = crossJump(j, cc.labelOf(target, cc.inlineIndex()));
     241           62334 :         if (cc.loop)
     242           36409 :             cc.loop->addJoin(index, false);
     243                 :     } else {
     244          141694 :         if (!scriptJoins.append(CrossJumpInScript(j, target, cc.inlineIndex())))
     245               0 :             return false;
     246          141694 :         if (cc.loop)
     247           44365 :             cc.loop->addJoin(scriptJoins.length() - 1, true);
     248                 :     }
     249          204028 :     return true;
     250                 : }
     251                 : 
     252                 : void
     253           33864 : StubCompiler::patchJoin(unsigned i, bool script, Assembler::Address address, AnyRegisterID reg)
     254                 : {
     255           33864 :     Jump &j = script ? scriptJoins[i].from : joins[i].from;
     256           33864 :     j.linkTo(masm.label(), &masm);
     257                 : 
     258           33864 :     if (reg.isReg())
     259           33433 :         masm.loadPayload(address, reg.reg());
     260                 :     else
     261             431 :         masm.loadDouble(address, reg.fpreg());
     262                 : 
     263           33864 :     j = masm.jump();
     264           33864 : }

Generated by: LCOV version 1.7