9edc07112b
When object support was first added to HHVM, a class named "Instance" was introduced (deriving from ObjectData) to represent instances of user defined classes. Since then, things have evolved and HPHPc and HPHPi have been retired, and now there really is no needed to have ObjectData and Instance be separate classes anymore. As a first step towards merging ObjectData and Instance together, this diff puts their definitions in the same .h file and puts their implementations in the same .cpp file. A few small changes were necessary to fix issues with cyclical includes: (1) Repo/emitter related parts of class.cpp and class.h were moved to class-emit.cpp and class-emit.h; (2) the contents of "vm/core_types.h" was moved to "base/types.h"; and (3) a few functions that didn't appear to be hot were moved from .h files and the corresponding .cpp files.
158 linhas
4.8 KiB
C++
158 linhas
4.8 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "hphp/runtime/vm/treadmill.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <pthread.h>
|
|
#include <stdio.h>
|
|
|
|
#include <list>
|
|
|
|
#include "hphp/util/trace.h"
|
|
#include "hphp/util/base.h"
|
|
#include "hphp/util/rank.h"
|
|
#include "hphp/runtime/base/macros.h"
|
|
#include "hphp/runtime/base/complex_types.h"
|
|
#include "hphp/runtime/vm/jit/translator-x64.h"
|
|
|
|
namespace HPHP { namespace Treadmill {
|
|
|
|
TRACE_SET_MOD(treadmill);
|
|
|
|
namespace {
|
|
static pthread_mutex_t s_genLock = PTHREAD_MUTEX_INITIALIZER;
|
|
static GenCount s_gen = 1;
|
|
static const GenCount kIdleGenCount = 0; // not processing any requests.
|
|
static GenCount* s_inflightRequests;
|
|
static int s_maxThreadID;
|
|
|
|
struct GenCountGuard {
|
|
GenCountGuard() {
|
|
checkRank(RankTreadmill);
|
|
pthread_mutex_lock(&s_genLock);
|
|
pushRank(RankTreadmill);
|
|
if (!s_inflightRequests) {
|
|
s_maxThreadID = 2;
|
|
s_inflightRequests = (GenCount*)calloc(sizeof(GenCount), s_maxThreadID);
|
|
static_assert(kIdleGenCount == 0, "kIdleGenCount should be zero");
|
|
}
|
|
}
|
|
~GenCountGuard() {
|
|
popRank(RankTreadmill);
|
|
pthread_mutex_unlock(&s_genLock);
|
|
}
|
|
};
|
|
}
|
|
|
|
static GenCount* idToCount(int threadID) {
|
|
if (threadID >= s_maxThreadID) {
|
|
int newSize = threadID + 1;
|
|
s_inflightRequests = (GenCount*)realloc(s_inflightRequests,
|
|
sizeof(GenCount) * newSize);
|
|
for (int i = s_maxThreadID; i < newSize; i++) {
|
|
s_inflightRequests[i] = kIdleGenCount;
|
|
}
|
|
s_maxThreadID = newSize;
|
|
}
|
|
return s_inflightRequests + threadID;
|
|
}
|
|
|
|
typedef std::list<WorkItem*> PendingTriggers;
|
|
static PendingTriggers s_tq;
|
|
|
|
// Inherently racy. We get a lower bound on the generation; presumably
|
|
// clients are aware of this, and are creating the trigger for an object
|
|
// that was reachable strictly in the past.
|
|
WorkItem::WorkItem() : m_gen(s_gen) {
|
|
}
|
|
|
|
void WorkItem::enqueue(WorkItem* gt) {
|
|
GenCountGuard g;
|
|
gt->m_gen = s_gen++;
|
|
s_tq.push_back(gt);
|
|
}
|
|
|
|
void startRequest(int threadId) {
|
|
GenCountGuard g;
|
|
assert(*idToCount(threadId) == kIdleGenCount);
|
|
TRACE(1, "tid %d start @gen %d\n", threadId, int(s_gen));
|
|
*idToCount(threadId) = s_gen;
|
|
}
|
|
|
|
void finishRequest(int threadId) {
|
|
TRACE(1, "tid %d finish\n", threadId);
|
|
std::vector<WorkItem*> toFire;
|
|
{
|
|
GenCountGuard g;
|
|
assert(*idToCount(threadId) != kIdleGenCount);
|
|
*idToCount(threadId) = kIdleGenCount;
|
|
|
|
// After finishing a request, check to see if we've allowed any triggers
|
|
// to fire.
|
|
PendingTriggers::iterator it = s_tq.begin();
|
|
PendingTriggers::iterator end = s_tq.end();
|
|
if (it != end) {
|
|
GenCount gen = (*it)->m_gen;
|
|
GenCount limit = s_gen + 1;
|
|
for (int i = 0; i < s_maxThreadID; ++i) {
|
|
if (s_inflightRequests[i] != kIdleGenCount &&
|
|
s_inflightRequests[i] < limit) {
|
|
limit = s_inflightRequests[i];
|
|
if (limit <= gen) break;
|
|
}
|
|
}
|
|
do {
|
|
TRACE(2, "considering delendum %d\n", int((*it)->m_gen));
|
|
if ((*it)->m_gen >= limit) {
|
|
TRACE(2, "not unreachable! %d\n", int((*it)->m_gen));
|
|
break;
|
|
}
|
|
toFire.push_back(*it);
|
|
it = s_tq.erase(it);
|
|
} while (it != end);
|
|
}
|
|
}
|
|
for (unsigned i = 0; i < toFire.size(); ++i) {
|
|
(*toFire[i])();
|
|
delete toFire[i];
|
|
}
|
|
}
|
|
|
|
FreeMemoryTrigger::FreeMemoryTrigger(void* ptr) : m_ptr(ptr) {
|
|
TRACE(3, "FreeMemoryTrigger @ %p, m_f %p\n", this, m_ptr);
|
|
}
|
|
|
|
void FreeMemoryTrigger::operator()() {
|
|
TRACE(3, "FreeMemoryTrigger: Firing @ %p , m_f %p\n", this, m_ptr);
|
|
free(m_ptr);
|
|
}
|
|
|
|
FreeClassTrigger::FreeClassTrigger(Class* cls) : m_cls(cls) {
|
|
TRACE(3, "FreeClassTrigger @ %p, cls %p\n", this, m_cls);
|
|
}
|
|
|
|
void FreeClassTrigger::operator()() {
|
|
TRACE(3, "FreeClassTrigger: Firing @ %p , cls %p\n", this, m_cls);
|
|
m_cls->atomicRelease();
|
|
}
|
|
|
|
void deferredFree(void* p) {
|
|
WorkItem::enqueue(new FreeMemoryTrigger(p));
|
|
}
|
|
|
|
}}
|