-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: I've wanted to do this for years, and this should help with the migration from TypedValue* to tv_lval. CallSpec::direct() now template-generates a function signature for the callee, using jit::Type equivalents of the C++ types (CallSpec::method() can be done later). This requires passing a properly-typed function pointer to CallSpec, so there are a few related changes to clean up places that were doing some information-destroying casting (especially irlower-minstr). I punted for builtin function calls, where there's no great way to get the actual function pointer right now. This didn't expose any real mismatches, but it did remind me that we still had a few helper functions that bitcast between double and int64_t, from before the JIT knew how to pass and return doubles to/from C++. Those have been cleaned up. We still use u?int64_t to return bools from a bunch of helpers, which I may clean up in a followup diff. Reviewed By: paulbiss Differential Revision: D8385908 fbshipit-source-id: c424d6ccd83b70ac267247e9244155426ee0053b
- Loading branch information
Showing
21 changed files
with
600 additions
and
340 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
+----------------------------------------------------------------------+ | ||
| HipHop for PHP | | ||
+----------------------------------------------------------------------+ | ||
| Copyright (c) 2010-present 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/jit/call-spec.h" | ||
|
||
#include "hphp/runtime/vm/jit/arg-group.h" | ||
|
||
#include "hphp/util/abi-cxx.h" | ||
|
||
#include <folly/Range.h> | ||
|
||
namespace HPHP { namespace jit { | ||
|
||
namespace { | ||
std::string show_types(const std::vector<Type>& ts) { | ||
std::string ret = "{"; | ||
auto sep = ""; | ||
for (auto& t : ts) { | ||
folly::format(&ret, "{}{}", sep, t); | ||
sep = ", "; | ||
} | ||
return ret + "}"; | ||
} | ||
|
||
template<typename F> | ||
void verify_return_type(Type ret, const CallDest& dest, F fail) { | ||
if (dest.type == DestType::TV) { | ||
// We really want equality here: TGen corresponds to a full TypedValue | ||
// being returned. | ||
if (ret == TGen) return; | ||
} else { | ||
if (ret <= dest.valueType) return; | ||
|
||
// Back before the JIT knew how to deal with byte-sized registers, we held | ||
// TBool in a zero-extended, 8-byte register. A number of runtime helpers | ||
// still return TBool as int64_t or uint64_t, so allow that mismatch here. | ||
if (dest.valueType <= TBool && ret <= TInt) return; | ||
|
||
// Some JIT types are much more specific than what we can express in C++, | ||
// so treat certain classes of types as equivalent. | ||
static auto constexpr special_types = { | ||
TPtrToGen, | ||
TLvalToGen, | ||
TBoxedInitCell, | ||
TObj, | ||
TStr, | ||
TArrLike, | ||
}; | ||
for (auto t : special_types) { | ||
if (ret <= t && dest.valueType.maybe(t)) return; | ||
} | ||
|
||
// SetElem's helper returns a StringData* that is sometimes statically | ||
// known to be TNullptr. Pointers in hhir aren't allowed to be null, so the | ||
// normal Type for StringData* is Str. Check for this special case here | ||
// rather than making all users of StringData* suboptimal. | ||
if (ret <= TStr && dest.valueType <= TNullptr) return; | ||
} | ||
|
||
fail("Return type mismatch"); | ||
} | ||
} | ||
|
||
bool CallSpec::verifySignature(const CallDest& dest, | ||
const std::vector<Type>& args) const { | ||
auto const type = m_typeKind.ptr(); | ||
if (!type) return true; | ||
if (kind() != Kind::Direct && kind() != Kind::Smashable) return true; | ||
|
||
auto fail = [&](auto&&... fmt) { | ||
auto const why = folly::sformat(std::forward<decltype(fmt)>(fmt)...); | ||
auto const func = getNativeFunctionName(this->address()); | ||
auto msg = folly::sformat( | ||
"Failed to verify signature for call to {}: {}\n\n", func, why | ||
); | ||
folly::format( | ||
&msg, "Arguments: {} -> {}\nSignature: {} -> {}", | ||
show_types(args), dest.valueType, show_types(type->params), type->ret | ||
); | ||
always_assert_flog(false, "{}", msg); | ||
}; | ||
|
||
verify_return_type(type->ret, dest, fail); | ||
|
||
size_t argi = 0, parami = 0; | ||
for (; parami < type->params.size() && argi < args.size(); | ||
++parami, ++argi) { | ||
auto const param = type->params[parami]; | ||
// TGen (for a TypedValue parameter) special: the value and type are passed | ||
// as two separate entries. Make sure both are present. | ||
if (param == TGen) { | ||
if (!(args[argi] <= TGen)) { | ||
fail("Incompatible type {} for Value half of TypedValue parameter {}", | ||
args[argi], parami); | ||
} | ||
if (++argi == args.size()) break; | ||
if (args[argi] != TBottom) { | ||
fail( | ||
"Incompatible type {} for DataType half of TypedValue parameter {}", | ||
args[argi], parami | ||
); | ||
} | ||
} else if (!(args[argi] <= param)) { | ||
// A few instructions pass Cls|Nullptr to helpers that take | ||
// Class*. Handle that special case here. | ||
if (!(param <= TCls && args[argi].maybe(TNullptr))) { | ||
fail( | ||
"Incompatible type {} for {} parameter {}", args[argi], param, parami | ||
); | ||
} | ||
} | ||
} | ||
|
||
if (parami != type->params.size() || argi != args.size()) { | ||
fail("Mismatch between argument and parameter counts"); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
}} |
Oops, something went wrong.