From 56ddbc6bd38620367af71d8431980528cb82bb37 Mon Sep 17 00:00:00 2001 From: Mirek Klimos Date: Fri, 21 Jun 2013 18:54:28 -0700 Subject: [PATCH] CreateCont opcode optimization - avoid unnecessary reference counting. Continuation argument values are copied to the continuation object and the locals are unset - in this way we don't need to change the reference coutners. --- hphp/runtime/base/tv_helpers.h | 16 +++++++++++----- hphp/runtime/vm/bytecode.cpp | 7 +++++-- hphp/runtime/vm/jit/hhbctranslator.cpp | 6 ++++-- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/hphp/runtime/base/tv_helpers.h b/hphp/runtime/base/tv_helpers.h index efe7bb4a3..2c91208f8 100644 --- a/hphp/runtime/base/tv_helpers.h +++ b/hphp/runtime/base/tv_helpers.h @@ -14,14 +14,14 @@ +----------------------------------------------------------------------+ */ +#ifndef incl_HPHP_TV_HELPERS_H_ +#define incl_HPHP_TV_HELPERS_H_ + #ifndef incl_HPHP_INSIDE_HPHP_COMPLEX_TYPES_H_ #error Directly including 'tv_helpers.h' is prohibited. \ Include 'complex_types.h' instead. #endif -#ifndef incl_HPHP_TV_HELPERS_H_ -#define incl_HPHP_TV_HELPERS_H_ - #include "hphp/runtime/base/types.h" namespace HPHP { @@ -216,11 +216,17 @@ inline void tvDupRef(RefData* fr, TypedValue* to) { } // Assumes 'fr' is live and 'to' is dead -// NOTE: this helper does not modify to->_count -inline void tvDup(const TypedValue* fr, TypedValue* to) { +// After this operation, 'fr' is dead and 'to' live. +inline void tvTeleport(const TypedValue* fr, TypedValue* to) { assert(tvIsPlausible(fr)); to->m_data.num = fr->m_data.num; to->m_type = fr->m_type; +} + +// Assumes 'fr' is live and 'to' is dead +// NOTE: this helper does not modify to->_count +inline void tvDup(const TypedValue* fr, TypedValue* to) { + tvTeleport(fr, to); tvRefcountedIncRef(to); } diff --git a/hphp/runtime/vm/bytecode.cpp b/hphp/runtime/vm/bytecode.cpp index 8eca2d7c5..75512e37b 100644 --- a/hphp/runtime/vm/bytecode.cpp +++ b/hphp/runtime/vm/bytecode.cpp @@ -383,7 +383,7 @@ void VarEnv::detach(ActRec* fp) { TypedValue** origLocs = !m_restoreLocations.empty() ? m_restoreLocations.back() - : reinterpret_cast(uintptr_t(this) + sizeof(VarEnv)); + : reinterpret_cast(uintptr_t(this) + sizeof(VarEnv)); for (Id i = 0; i < numLocals; i++) { m_nvTable->resettle(func->localVarName(i), origLocs[i]); @@ -6694,7 +6694,10 @@ static inline void setContVar(const Func* genFunc, c_Continuation* cont) { Id destId = genFunc->lookupVarId(name); if (destId != kInvalidId) { - tvDup(src, frame_local(cont->actRec(), destId)); + // Copy the value of the local to the cont object and set the + // local to uninit so that we don't need to change refcounts. + tvTeleport(src, frame_local(cont->actRec(), destId)); + tvWriteUninit(src); } else { ActRec *contFP = cont->actRec(); if (!contFP->hasVarEnv()) { diff --git a/hphp/runtime/vm/jit/hhbctranslator.cpp b/hphp/runtime/vm/jit/hhbctranslator.cpp index dd25a71a2..f8d248363 100644 --- a/hphp/runtime/vm/jit/hhbctranslator.cpp +++ b/hphp/runtime/vm/jit/hhbctranslator.cpp @@ -1033,8 +1033,10 @@ void HhbcTranslator::emitCreateCont(Id funNameStrId) { // We must generate an AssertLoc because we don't have tracelet // guards on the object type in these outer generator functions. gen(AssertLoc, Type::Gen, LocalId(i), m_tb->fp()); - auto const loc = gen(IncRef, ldLoc(i)); - gen(StMem, contAR, cns(-cellsToBytes(params[i] + 1)), loc); + // Copy the value of the local to the cont object and set the + // local to uninit so that we don't need to change refcounts. + gen(StMem, contAR, cns(-cellsToBytes(params[i] + 1)), ldLoc(i)); + gen(StLoc, LocalId(i), m_tb->fp(), m_tb->genDefUninit()); } if (fillThis) { assert(thisId != kInvalidId);