Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions builtin-functions/kphp-full/_functions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,13 @@ interface RpcFunction {
public function typedFetch() : @tl\RpcFunctionFetcher;
}

/**
* @kphp-required
*/
interface VK\TL\RpcFunctionFactory {
public function createFunction(int $magic) : @tl\RpcFunction;
}

/** @kphp-tl-class */
interface RpcFunctionReturnResult {}

Expand All @@ -1036,6 +1043,8 @@ function typed_rpc_tl_query_result_synchronously (int[] $query_ids) ::: @tl\RpcR
/** @kphp-extern-func-info can_throw */
function rpc_server_fetch_request() ::: @tl\RpcFunction;
/** @kphp-extern-func-info can_throw */
function rpc_server_fetch_request2(VK\TL\RpcFunctionFactory $factory) ::: @tl\RpcFunction;
/** @kphp-extern-func-info can_throw */
function rpc_server_store_response(@tl\RpcFunctionReturnResult $response) ::: void;

/** @kphp-extern-func-info can_throw resumable cpp_template_call */
Expand Down
10 changes: 10 additions & 0 deletions builtin-functions/kphp-light/stdlib/rpc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ interface RpcFunction {
public function typedFetch() : @tl\RpcFunctionFetcher;
}

/**
* @kphp-required
*/
interface VK\TL\RpcFunctionFactory {
public function createFunction(int $magic) : @tl\RpcFunction;
}

/** @kphp-tl-class */
interface RpcFunctionReturnResult {}

Expand Down Expand Up @@ -105,6 +112,9 @@ function store_error ($error_code ::: int, $error_text ::: string) ::: bool;
/** @kphp-extern-func-info can_throw */
function rpc_server_fetch_request() ::: @tl\RpcFunction;

/** @kphp-extern-func-info can_throw */
function rpc_server_fetch_request2(VK\TL\RpcFunctionFactory $factory) ::: @tl\RpcFunction;

/** @kphp-extern-func-info can_throw interruptible */
function rpc_server_store_response(@tl\RpcFunctionReturnResult $response) ::: void;

Expand Down
7 changes: 7 additions & 0 deletions compiler/code-gen/declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,13 @@ void ClassDeclaration::compile(CodeGenerator &W) const {
W << "return " << f_tl_cpp_struct_name << "::typed_store(this);" << NL;
W << END << NL;
}
if (tl2cpp::is_php_class_a_tl_function_not_in_tlo(klass)) {
// typedStore() should never return null for such a function, so this code is never executed
W << NL;
FunctionSignatureGenerator(W).set_final().set_const_this() << "std::unique_ptr<tl_func_base> store() " << BEGIN;
W << "return std::unique_ptr<tl_func_base>{};" << NL;
W << END << NL;
}

compile_job_worker_shared_memory_piece_methods(W, true);

Expand Down
4 changes: 4 additions & 0 deletions compiler/code-gen/files/tl2cpp/tl2cpp-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ bool is_php_class_a_tl_function(ClassPtr klass) {
return klass->is_tl_class && klass->implements.size() == 1 && vk::string_view{klass->implements.front()->name}.ends_with("RpcFunction");
}

bool is_php_class_a_tl_function_not_in_tlo(ClassPtr klass) {
return !klass->is_tl_class && klass->implements.size() == 1 && vk::string_view{klass->implements.front()->name}.ends_with("RpcFunction");
}

// classes VK\TL\*\Types\* are a non-interface types that correspond to the TL-constructors
// (or non-polymorphic types with a single constructor that was inlined)
bool is_php_class_a_tl_constructor(ClassPtr klass) {
Expand Down
1 change: 1 addition & 0 deletions compiler/code-gen/files/tl2cpp/tl2cpp-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ std::string get_php_runtime_type(const vk::tlo_parsing::combinator *c, bool wrap
std::string get_php_runtime_type(const vk::tlo_parsing::type *t);

bool is_php_class_a_tl_function(ClassPtr klass);
bool is_php_class_a_tl_function_not_in_tlo(ClassPtr klass);
bool is_php_class_a_tl_constructor(ClassPtr klass);
bool is_php_class_a_tl_polymorphic_type(ClassPtr klass);
bool is_php_class_a_tl_array_item(ClassPtr klass);
Expand Down
28 changes: 27 additions & 1 deletion compiler/code-gen/files/tl2cpp/tl2cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,33 @@ void write_rpc_server_functions(CodeGenerator &W) {
}
W << deps << NL;
W << ExternInclude{G->settings().runtime_headers.get()} << NL;
FunctionSignatureGenerator(W) << "class_instance<C$VK$TL$RpcFunction> f$rpc_server_fetch_request() " << BEGIN;
FunctionSignatureGenerator(W) << "class_instance<C$VK$TL$RpcFunction> f$rpc_server_fetch_request2(const class_instance<C$VK$TL$RpcFunctionFactory> & factory)" << BEGIN;
W << "auto start = tl_parse_save_pos();" << NL;
W << "auto function_magic = static_cast<unsigned int>(f$fetch_int());" << NL;
W << "int tl_version = function_magic == 0x30324c54 ? 2 : 1; // TL2 marker" << NL;
W << "if (tl_version == 2) " << BEGIN;
W << "function_magic = static_cast<unsigned int>(f$fetch_int());" << NL;
W << END << NL;
W << "(void)tl_parse_restore_pos(start);" << NL;
W << "auto php_fun = f$VK$TL$RpcFunctionFactory$$createFunction(factory, function_magic);" << NL;
W << "if (php_fun.is_null())" << BEGIN
<< "return f$rpc_server_fetch_request();" << NL
<< END << NL
<< "CurrentTlQuery::get().set_current_tl_function(f$VK$TL$RpcFunction$$getTLFunctionName(php_fun));" << NL
<< "auto custom_fetcher = f$VK$TL$RpcFunction$$typedFetch(php_fun);" << NL
<< "CHECK_EXCEPTION(" << NL
<< " php_warning(\"Exception when calling typedFetch for function magic: 0x%08x tl_version: %d\", function_magic, tl_version);" << NL
<< " return {};" << NL
<< ")" << NL
<< "if (custom_fetcher.is_null())" << BEGIN
<< "php_warning(\"function returned by factory must not return null from typedFetch(): 0x%08x tl_version: %d\", function_magic, tl_version);" << NL
<< "return {};" << NL
<< END << NL
<< "CurrentRpcServerQuery::get().save(make_tl_func_base_simple_wrapper(std::move(custom_fetcher)));" << NL
<< "return php_fun;" << NL;
W << END << NL;

FunctionSignatureGenerator(W) << "class_instance<C$VK$TL$RpcFunction> f$rpc_server_fetch_request()" << BEGIN;
// PHP typedFetch expects full body with optional TL2 marker and function magic,
// otherwise it cannot determine TL version.
// C++ rpc_server_typed_fetch expects body after function magic.
Expand Down
6 changes: 0 additions & 6 deletions compiler/pipes/check-tl-classes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ void verify_class_against_repr(ClassPtr class_id, const vk::tl::PhpClassRepresen
kphp_error_return(class_id->is_interface() == repr.is_interface,
fmt_format("Tl-class '{}' is{} expected to be an interface", class_id->name, repr.is_interface ? "" : " not"));

for (const auto &child : class_id->derived_classes) {
kphp_error_return(child->phpdoc->has_tag(PhpDocType::kphp_tl_class),
fmt_format("Class '{}' is expected to be tl-class, because it inherits from tl-class '{}'",
child->name, class_id->name));
}

if (repr.parent) {
const std::string expected = repr.parent->php_class_namespace + "\\" + repr.parent->php_class_name;
kphp_error_return(class_id->implements.size() == 1,
Expand Down
3 changes: 3 additions & 0 deletions runtime-light/stdlib/rpc/rpc-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ inline bool f$rpc_parse(const Optional<string>& new_rpc_data) noexcept {
// 2. switch over all @kphp functions
// 3. tl_func_state storing inside the CurrentRpcServerQuery
class_instance<C$VK$TL$RpcFunction> f$rpc_server_fetch_request() noexcept;
// calls user-provided factory, if it returns !null, sets up returned function for processing,
// otherwise, calls f$rpc_server_fetch_request()
class_instance<C$VK$TL$RpcFunction> f$rpc_server_fetch_request2(const class_instance<C$VK$TL$RpcFunctionFactory>& factory) noexcept;

inline kphp::coro::task<bool> f$store_error(int64_t error_code, string error_msg) noexcept {
if (tl::is_int32_overflow(error_code)) [[unlikely]] {
Expand Down
25 changes: 25 additions & 0 deletions runtime-light/stdlib/rpc/rpc-tl-function.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,31 @@ struct C$VK$TL$RpcFunctionFetcher : abstract_refcountable_php_interface {
~C$VK$TL$RpcFunctionFetcher() override = default;
};

struct C$VK$TL$RpcFunctionFactory : abstract_refcountable_php_interface {
virtual const char* get_class() const {
return "VK\\TL\\RpcFunctionFactory";
}
virtual int32_t get_hash() const {
std::string_view name_view{C$VK$TL$RpcFunctionFactory::get_class()};
return static_cast<int32_t>(vk::murmur_hash<uint32_t>(name_view.data(), name_view.size()));
}

virtual void accept(ToArrayVisitor&) noexcept {}
virtual void accept(CommonMemoryEstimateVisitor&) noexcept {}
virtual void accept(InstanceReferencesCountingVisitor&) noexcept {}
virtual void accept(InstanceDeepCopyVisitor&) noexcept {}
virtual void accept(InstanceDeepDestroyVisitor&) noexcept {}

virtual size_t virtual_builtin_sizeof() const noexcept {
return 0;
}
virtual C$VK$TL$RpcFunctionFactory* virtual_builtin_clone() const noexcept {
return nullptr;
}

virtual ~C$VK$TL$RpcFunctionFactory() = default;
};

// function call response — ReqResult from the TL scheme — is a rpcResponseOk|rpcResponseHeader|rpcResponseError;
// if it's rpcResponseOk or rpcResponseHeader, then their bodies can be retrieved by a fetcher that was returned by a store
struct C$VK$TL$RpcResponse : abstract_refcountable_php_interface {
Expand Down
1 change: 1 addition & 0 deletions runtime-light/stdlib/rpc/rpc-tl-kphp-request.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "runtime-light/stdlib/rpc/rpc-tl-query.h"
#include "runtime-light/stdlib/rpc/rpc-tl-request.h"

class_instance<C$VK$TL$RpcFunction> f$VK$TL$RpcFunctionFactory$$createFunction(class_instance<C$VK$TL$RpcFunctionFactory> const& arg, int64_t magic) noexcept;
int64_t f$VK$TL$RpcFunction$$getTLFunctionMagic(class_instance<C$VK$TL$RpcFunction> const& arg) noexcept;
string f$VK$TL$RpcFunction$$getTLFunctionName(class_instance<C$VK$TL$RpcFunction> const& arg) noexcept;
class_instance<C$VK$TL$RpcFunctionFetcher> f$VK$TL$RpcFunction$$typedStore(class_instance<C$VK$TL$RpcFunction> const& arg) noexcept;
Expand Down
25 changes: 25 additions & 0 deletions runtime/tl/rpc_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,31 @@ struct C$VK$TL$RpcFunctionFetcher : abstract_refcountable_php_interface {
virtual ~C$VK$TL$RpcFunctionFetcher() = default;
};

struct C$VK$TL$RpcFunctionFactory : abstract_refcountable_php_interface {
virtual const char* get_class() const {
return "VK\\TL\\RpcFunctionFactory";
}
virtual int32_t get_hash() const {
std::string_view name_view{C$VK$TL$RpcFunctionFactory::get_class()};
return static_cast<int32_t>(vk::murmur_hash<uint32_t>(name_view.data(), name_view.size()));
}

virtual void accept(ToArrayVisitor&) noexcept {}
virtual void accept(CommonMemoryEstimateVisitor&) noexcept {}
virtual void accept(InstanceReferencesCountingVisitor&) noexcept {}
virtual void accept(InstanceDeepCopyVisitor&) noexcept {}
virtual void accept(InstanceDeepDestroyVisitor&) noexcept {}

virtual size_t virtual_builtin_sizeof() const noexcept {
return 0;
}
virtual C$VK$TL$RpcFunctionFactory* virtual_builtin_clone() const noexcept {
return nullptr;
}

virtual ~C$VK$TL$RpcFunctionFactory() = default;
};

// function call response — ReqResult from the TL scheme — is a rpcResponseOk|rpcResponseHeader|rpcResponseError;
// if it's rpcResponseOk or rpcResponseHeader, then their bodies can be retrieved by a fetcher that was returned by a store
struct C$VK$TL$RpcResponse : abstract_refcountable_php_interface {
Expand Down
1 change: 1 addition & 0 deletions runtime/tl/rpc_request.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "runtime/tl/tl_builtins.h"
#include "runtime/tl/tl_func_base.h"

class_instance<C$VK$TL$RpcFunction> f$VK$TL$RpcFunctionFactory$$createFunction(class_instance<C$VK$TL$RpcFunctionFactory> const& arg, int64_t magic) noexcept;
int64_t f$VK$TL$RpcFunction$$getTLFunctionMagic(class_instance<C$VK$TL$RpcFunction> const& arg) noexcept;
string f$VK$TL$RpcFunction$$getTLFunctionName(class_instance<C$VK$TL$RpcFunction> const& arg) noexcept;
class_instance<C$VK$TL$RpcFunctionFetcher> f$VK$TL$RpcFunction$$typedStore(class_instance<C$VK$TL$RpcFunction> const& arg) noexcept;
Expand Down
1 change: 1 addition & 0 deletions runtime/tl/rpc_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ struct C$VK$TL$RpcFunction;
struct C$VK$TL$RpcFunctionReturnResult;

class_instance<C$VK$TL$RpcFunction> f$rpc_server_fetch_request() noexcept;
class_instance<C$VK$TL$RpcFunction> f$rpc_server_fetch_request2(const class_instance<C$VK$TL$RpcFunctionFactory>& factory) noexcept;
void f$rpc_server_store_response(const class_instance<C$VK$TL$RpcFunctionReturnResult>& response) noexcept;
Loading