Skip to content

Commit

Permalink
kill nullability of IC
Browse files Browse the repository at this point in the history
Summary: kill the nullability of the implicit context. In future, if we ever want a null IC, we will implement a separate object representing null IC

Reviewed By: jano

Differential Revision: D57465829

fbshipit-source-id: ecaca8bfb83b23b66c68352317e689c4536b8889
  • Loading branch information
Max Trivedi authored and facebook-github-bot committed May 19, 2024
1 parent 749b7f5 commit 36b218e
Show file tree
Hide file tree
Showing 12 changed files with 32 additions and 71 deletions.
2 changes: 1 addition & 1 deletion hphp/doc/bytecode.specification
Original file line number Diff line number Diff line change
Expand Up @@ -3206,7 +3206,7 @@ RaiseClassStringConversionNotice [] -> []
Raises a notice indicating an implicit class to string conversion.
This notice is emitted at a sampled rate through a runtime option.

SetImplicitContextByValue [C:?Obj] -> [C:?Obj]
SetImplicitContextByValue [C:Obj] -> [C:Obj]

Sets the implicit context to %1 and returns the previous implicit context.

Expand Down
4 changes: 2 additions & 2 deletions hphp/doc/ir.specification
Original file line number Diff line number Diff line change
Expand Up @@ -1366,7 +1366,7 @@ To string conversions:

Load the ArrayData* containing the generics attached to the RFuncData in S0

| LdImplicitContext, D(Obj|InitNull), NA, NF
| LdImplicitContext, D(Obj), NA, NF

Loads implicit context from RDS.

Expand Down Expand Up @@ -1801,7 +1801,7 @@ ReqBindJmp and CallFuncEntry.
Store the TypedValue in S0 into the specified RDS handle. Must store the aux
bits if `includeAux` is true.

| StImplicitContext, ND, S(Obj|InitNull), NF
| StImplicitContext, ND, S(Obj), NF

Sets the implicit context to S0.

Expand Down
2 changes: 1 addition & 1 deletion hphp/hhbbc/interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5483,7 +5483,7 @@ void in(ISS& env, const bc::AwaitAll& op) {

void in(ISS& env, const bc::SetImplicitContextByValue&) {
popC(env);
push(env, TOptObj);
push(env, TObj);
}

const StaticString
Expand Down
2 changes: 2 additions & 0 deletions hphp/runtime/base/execution-context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1745,6 +1745,7 @@ void ExecutionContext::resumeAsyncFunc(Resumable* resumable,
ObjectData* freeObj,
const TypedValue awaitResult) {
assertx(regState() == VMRegState::CLEAN);
assertx(*ImplicitContext::activeCtx);
SCOPE_EXIT { assertx(regState() == VMRegState::CLEAN); };

auto fp = resumable->actRec();
Expand Down Expand Up @@ -1789,6 +1790,7 @@ void ExecutionContext::resumeAsyncFuncThrow(Resumable* resumable,
assertx(exception);
assertx(exception->instanceof(SystemLib::getThrowableClass()));
assertx(regState() == VMRegState::CLEAN);
assertx(*ImplicitContext::activeCtx);
SCOPE_EXIT { assertx(regState() == VMRegState::CLEAN); };

auto fp = resumable->actRec();
Expand Down
2 changes: 2 additions & 0 deletions hphp/runtime/ext/asio/ext_async-function-wait-handle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ c_AsyncFunctionWaitHandle::Create(const ActRec* fp,
waitHandle->m_packedTailFrameIds = -1;
assertx(!waitHandle->hasTailFrames());
waitHandle->initialize(child);
assertx(*ImplicitContext::activeCtx);
waitHandle->m_implicitContext = *ImplicitContext::activeCtx;
return waitHandle;
}
Expand Down Expand Up @@ -194,6 +195,7 @@ void c_AsyncFunctionWaitHandle::await(Offset suspendOffset,
req::ptr<c_WaitableWaitHandle>&& child) {
// Prepare child for establishing dependency. May throw.
prepareChild(child.get());
assertx(*ImplicitContext::activeCtx);
this->m_implicitContext = *ImplicitContext::activeCtx;

// Suspend the async function.
Expand Down
1 change: 1 addition & 0 deletions hphp/runtime/ext/asio/ext_async-generator-wait-handle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ c_AsyncGeneratorWaitHandle::Create(const ActRec* fp,
gen->resumable()->setResumeAddr(resumeAddr, suspendOffset);
gen->attachWaitHandle(req::ptr<c_AsyncGeneratorWaitHandle>(wh));

assertx(*ImplicitContext::activeCtx);
wh.get()->m_implicitContext = *ImplicitContext::activeCtx;
return wh.detach();
}
Expand Down
2 changes: 2 additions & 0 deletions hphp/runtime/ext/asio/ext_waitable-wait-handle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ void c_WaitableWaitHandle::join() {

assertx(!isFinished());

assertx(*ImplicitContext::activeCtx);
auto const context = *ImplicitContext::activeCtx;

AsioSession* session = AsioSession::Get();
Expand All @@ -61,6 +62,7 @@ void c_WaitableWaitHandle::join() {
// run queues until we are finished
session->getCurrentContext()->runUntil(this);
assertx(isFinished());
assertx(context);
*ImplicitContext::activeCtx = context;
}

Expand Down
16 changes: 10 additions & 6 deletions hphp/runtime/ext/hh/ext_implicit_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ Object create_new_IC() {
} // namespace

bool HHVM_FUNCTION(is_inaccessible) {
assertx(*ImplicitContext::activeCtx);
auto const obj = *ImplicitContext::activeCtx;
if (!obj) return false;
auto const context = Native::data<ImplicitContext>(obj);
// In future, if we add a nullstate, that will be implemented
// using an object to represent the null state
return context->m_state == ImplicitContext::State::Inaccessible;
}

Expand All @@ -100,8 +102,8 @@ Object initInaccessibleConext() {
};

String HHVM_FUNCTION(get_state_unsafe) {
assertx(*ImplicitContext::activeCtx);
auto const obj = *ImplicitContext::activeCtx;
if (!obj) return String{s_ICStateNull.get()};
auto const context = Native::data<ImplicitContext>(obj);

switch (context->m_state) {
Expand All @@ -118,8 +120,8 @@ String HHVM_FUNCTION(get_state_unsafe) {
}

TypedValue HHVM_FUNCTION(get_implicit_context, StringArg key) {
assertx(*ImplicitContext::activeCtx);
auto const obj = *ImplicitContext::activeCtx;
if (!obj) return make_tv<KindOfNull>();
auto const context = Native::data<ImplicitContext>(obj);

switch (context->m_state) {
Expand All @@ -141,9 +143,9 @@ TypedValue HHVM_FUNCTION(get_implicit_context, StringArg key) {
not_reached();
}

Variant HHVM_FUNCTION(get_whole_implicit_context) {
ObjectRet HHVM_FUNCTION(get_whole_implicit_context) {
assertx(*ImplicitContext::activeCtx);
auto const obj = *ImplicitContext::activeCtx;
if (!obj) return init_null();
return Object{obj};
}

Expand All @@ -153,6 +155,7 @@ Variant HHVM_FUNCTION(get_whole_implicit_context) {
* the IC should stay alive due to being stored in s_memokey_to_IC
*/
int64_t HHVM_FUNCTION(get_implicit_context_memo_key) {
assertx(*ImplicitContext::activeCtx);
auto const obj = *ImplicitContext::activeCtx;
return reinterpret_cast<int64_t>(obj);
}
Expand All @@ -162,8 +165,8 @@ int64_t HHVM_FUNCTION(get_implicit_context_memo_key) {
* Only to be used for testing
*/
Array HHVM_FUNCTION(get_implicit_context_debug_info) {
assertx(*ImplicitContext::activeCtx);
auto const obj = *ImplicitContext::activeCtx;
if (!obj) return Array{};
auto const context = Native::data<ImplicitContext>(obj);

if (context->m_state != ImplicitContext::State::Value) {
Expand Down Expand Up @@ -195,6 +198,7 @@ Object HHVM_FUNCTION(create_implicit_context, StringArg keyarg,
throw_implicit_context_exception(
"Implicit context keys cannot be empty or start with _");
}
assertx(*ImplicitContext::activeCtx);
auto const prev = *ImplicitContext::activeCtx;

// Compute memory key first
Expand Down
2 changes: 1 addition & 1 deletion hphp/runtime/ext/hh/ext_implicit_context.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ final class ImplicitContextData {}
function get_implicit_context(string $key)[zoned]: mixed;

<<__Native>>
function get_whole_implicit_context()[zoned]: ?ImplicitContextData;
function get_whole_implicit_context()[zoned]: ImplicitContextData;

/**
* Creates implicit context $context keyed by $key.
Expand Down
20 changes: 3 additions & 17 deletions hphp/runtime/vm/bytecode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5187,26 +5187,12 @@ OPTBLD_INLINE void iopWHResult() {

OPTBLD_INLINE void iopSetImplicitContextByValue() {
auto const tv = *vmStack().topC();
auto const obj = [&]() -> ObjectData* {
if (tvIsNull(tv)) return nullptr;
if (UNLIKELY(!tvIsObject(tv))) {
SystemLib::throwInvalidArgumentExceptionObject(
"Invalid input to SetImplicitContextByValue");
}
return tv.m_data.pobj;
}();
assertx(tvIsObject(tv));
auto const obj = tv.m_data.pobj;
auto const prev = *ImplicitContext::activeCtx;
*ImplicitContext::activeCtx = obj;
vmStack().discard();

if (!prev) {
vmStack().pushNull();
} else {
vmStack().pushObject(prev);
}

// Decref after discarding so that if we are pushing the same object back,
// avoid refcount going to zero
vmStack().pushObject(prev);
tvDecRefGen(tv);
}

Expand Down
17 changes: 3 additions & 14 deletions hphp/runtime/vm/jit/irgen-builtin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1251,19 +1251,8 @@ SSATmp* opt_meth_caller_get_method(IRGS& env, const ParamPrep& params) {

SSATmp* opt_get_implicit_context_memo_key(IRGS& env, const ParamPrep& params) {
if (params.size() != 0) return nullptr;
return cond(
env,
[&] (Block* taken) {
auto const ctx = gen(env, LdImplicitContext);
return gen(env, CheckType, TObj, taken, ctx);
},
[&] (SSATmp* ctx) {
return gen(env, LdImplicitContextMemoKey, ctx);
},
[&] {
return cns(env, 0);
}
);
auto const ctx = gen(env, LdImplicitContext);
return gen(env, LdImplicitContextMemoKey, ctx);
}

SSATmp* opt_class_to_classname(IRGS& env, const ParamPrep& params) {
Expand Down Expand Up @@ -2643,7 +2632,7 @@ void emitSilence(IRGS& env, Id localId, SilenceOp subop) {

void emitSetImplicitContextByValue(IRGS& env) {
auto const tv = topC(env);
if (!tv->type().subtypeOfAny(TInitNull, TObj)) return interpOne(env);
if(!tv->isA(TObj)) return interpOne(env);

auto const prev = gen(env, LdImplicitContext);
gen(env, StImplicitContext, tv);
Expand Down
33 changes: 4 additions & 29 deletions hphp/runtime/vm/jit/irlower-load-store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,19 +267,7 @@ void cgLdImplicitContext(IRLS& env, const IRInstruction* inst) {
markRDSAccess(v, ImplicitContext::activeCtx.handle());

auto const dst = dstLoc(env, inst, 0);
auto const sf = v.makeReg();
v << load{
rvmtl()[ImplicitContext::activeCtx.handle()],
dst.reg(0) /* data */
};
v << testq{dst.reg(0), dst.reg(0), sf};
v << cmovb{
CC_Z,
sf,
v.cns(TObj.toDataType()),
v.cns(TInitNull.toDataType()),
dst.reg(1) /* type */
};
v << load{rvmtl()[ImplicitContext::activeCtx.handle()], dst.reg(0)};
}

void cgLdImplicitContextMemoKey(IRLS& env, const IRInstruction* inst) {
Expand All @@ -292,25 +280,12 @@ void cgLdImplicitContextMemoKey(IRLS& env, const IRInstruction* inst) {

void cgStImplicitContext(IRLS& env, const IRInstruction* inst) {
auto& v = vmain(env);
auto const src = inst->src(0);
assertx(inst->src(0)->isA(TObj));

auto const data = srcLoc(env, inst, 0).reg(0);
auto const type = srcLoc(env, inst, 0).reg(1);
markRDSAccess(v, ImplicitContext::activeCtx.handle());

if (src->isA(TInitNull)) {
v << store{v.cns(nullptr), rvmtl()[ImplicitContext::activeCtx.handle()]};
} else if (src->isA(TObj)) {
v << store{data, rvmtl()[ImplicitContext::activeCtx.handle()]};
} else {
assertx(src->isA(TObj|TInitNull));
emitTypeTest(v, env, TInitNull, data, type, v.makeReg(),
[&] (ConditionCode cc, Vreg sf) {
auto const result = v.makeReg();
v << cmovq{cc, sf, v.cns(nullptr), data, result};
v << store{result, rvmtl()[ImplicitContext::activeCtx.handle()]};
}
);
}
v << store{data, rvmtl()[ImplicitContext::activeCtx.handle()]};
}

void cgDbgTrashMem(IRLS& env, const IRInstruction* inst) {
Expand Down

0 comments on commit 36b218e

Please sign in to comment.