You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-15 13:51:40 +00:00
Merge pull request #91192 from vnen/gdscript-validated-native-static-calls
GDScript: Perform validated calls with static methods
This commit is contained in:
@@ -1196,11 +1196,8 @@ void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) {
|
void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) {
|
||||||
bool is_validated = false;
|
|
||||||
|
|
||||||
MethodBind *method = ClassDB::get_method(p_class, p_method);
|
MethodBind *method = ClassDB::get_method(p_class, p_method);
|
||||||
|
|
||||||
if (!is_validated) {
|
|
||||||
// Perform regular call.
|
// Perform regular call.
|
||||||
append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1);
|
append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1);
|
||||||
for (int i = 0; i < p_arguments.size(); i++) {
|
for (int i = 0; i < p_arguments.size(); i++) {
|
||||||
@@ -1213,6 +1210,35 @@ void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target
|
|||||||
ct.cleanup();
|
ct.cleanup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GDScriptByteCodeGenerator::write_call_native_static_validated(const GDScriptCodeGenerator::Address &p_target, MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {
|
||||||
|
Variant::Type return_type = Variant::NIL;
|
||||||
|
bool has_return = p_method->has_return();
|
||||||
|
|
||||||
|
if (has_return) {
|
||||||
|
PropertyInfo return_info = p_method->get_return_info();
|
||||||
|
return_type = return_info.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
CallTarget ct = get_call_target(p_target, return_type);
|
||||||
|
|
||||||
|
if (has_return) {
|
||||||
|
Variant::Type temp_type = temporaries[ct.target.address].type;
|
||||||
|
if (temp_type != return_type) {
|
||||||
|
write_type_adjust(ct.target, return_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GDScriptFunction::Opcode code = p_method->has_return() ? GDScriptFunction::OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN : GDScriptFunction::OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN;
|
||||||
|
append_opcode_and_argcount(code, 1 + p_arguments.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < p_arguments.size(); i++) {
|
||||||
|
append(p_arguments[i]);
|
||||||
|
}
|
||||||
|
append(ct.target);
|
||||||
|
append(p_arguments.size());
|
||||||
|
append(p_method);
|
||||||
|
ct.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {
|
void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {
|
||||||
|
|||||||
@@ -518,6 +518,7 @@ public:
|
|||||||
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
|
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
|
||||||
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
|
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
|
||||||
virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) override;
|
virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) override;
|
||||||
|
virtual void write_call_native_static_validated(const Address &p_target, MethodBind *p_method, const Vector<Address> &p_arguments) override;
|
||||||
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
|
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
|
||||||
virtual void write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
|
virtual void write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
|
||||||
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
|
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ public:
|
|||||||
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
|
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
|
||||||
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
|
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
|
||||||
virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
|
virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
|
||||||
|
virtual void write_call_native_static_validated(const Address &p_target, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
|
||||||
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
|
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
|
||||||
virtual void write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
|
virtual void write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
|
||||||
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
|
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
|
||||||
|
|||||||
@@ -673,7 +673,15 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
|||||||
} else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") &&
|
} else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") &&
|
||||||
ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) {
|
ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) {
|
||||||
// It's a static native method call.
|
// It's a static native method call.
|
||||||
gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments);
|
StringName class_name = static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name;
|
||||||
|
MethodBind *method = ClassDB::get_method(class_name, subscript->attribute->name);
|
||||||
|
if (_can_use_validate_call(method, arguments)) {
|
||||||
|
// Exact arguments, use validated call.
|
||||||
|
gen->write_call_native_static_validated(result, method, arguments);
|
||||||
|
} else {
|
||||||
|
// Not exact arguments, use regular static call
|
||||||
|
gen->write_call_native_static(result, class_name, subscript->attribute->name, arguments);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
|
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
|
||||||
if (r_error) {
|
if (r_error) {
|
||||||
|
|||||||
@@ -678,6 +678,50 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
|
|||||||
incr += 4 + argc;
|
incr += 4 + argc;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN: {
|
||||||
|
int instr_var_args = _code_ptr[++ip];
|
||||||
|
text += "call native static method validated (return) ";
|
||||||
|
MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
|
||||||
|
int argc = _code_ptr[ip + 1 + instr_var_args];
|
||||||
|
text += DADDR(1 + argc) + " = ";
|
||||||
|
text += method->get_instance_class();
|
||||||
|
text += ".";
|
||||||
|
text += method->get_name();
|
||||||
|
text += "(";
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
text += ", ";
|
||||||
|
text += DADDR(1 + i);
|
||||||
|
}
|
||||||
|
text += ")";
|
||||||
|
incr = 4 + argc;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN: {
|
||||||
|
int instr_var_args = _code_ptr[++ip];
|
||||||
|
|
||||||
|
text += "call native static method validated (no return) ";
|
||||||
|
|
||||||
|
MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
|
||||||
|
|
||||||
|
int argc = _code_ptr[ip + 1 + instr_var_args];
|
||||||
|
|
||||||
|
text += method->get_instance_class();
|
||||||
|
text += ".";
|
||||||
|
text += method->get_name();
|
||||||
|
text += "(";
|
||||||
|
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
text += ", ";
|
||||||
|
}
|
||||||
|
text += DADDR(1 + i);
|
||||||
|
}
|
||||||
|
text += ")";
|
||||||
|
|
||||||
|
incr = 4 + argc;
|
||||||
|
} break;
|
||||||
|
|
||||||
case OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN: {
|
case OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN: {
|
||||||
int instr_var_args = _code_ptr[++ip];
|
int instr_var_args = _code_ptr[++ip];
|
||||||
text += "call method-bind validated (return) ";
|
text += "call method-bind validated (return) ";
|
||||||
|
|||||||
@@ -264,6 +264,8 @@ public:
|
|||||||
OPCODE_CALL_METHOD_BIND_RET,
|
OPCODE_CALL_METHOD_BIND_RET,
|
||||||
OPCODE_CALL_BUILTIN_STATIC,
|
OPCODE_CALL_BUILTIN_STATIC,
|
||||||
OPCODE_CALL_NATIVE_STATIC,
|
OPCODE_CALL_NATIVE_STATIC,
|
||||||
|
OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN,
|
||||||
|
OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN,
|
||||||
OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN,
|
OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN,
|
||||||
OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN,
|
OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN,
|
||||||
OPCODE_AWAIT,
|
OPCODE_AWAIT,
|
||||||
|
|||||||
@@ -261,6 +261,8 @@ void (*type_init_function_table[])(Variant *) = {
|
|||||||
&&OPCODE_CALL_METHOD_BIND_RET, \
|
&&OPCODE_CALL_METHOD_BIND_RET, \
|
||||||
&&OPCODE_CALL_BUILTIN_STATIC, \
|
&&OPCODE_CALL_BUILTIN_STATIC, \
|
||||||
&&OPCODE_CALL_NATIVE_STATIC, \
|
&&OPCODE_CALL_NATIVE_STATIC, \
|
||||||
|
&&OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN, \
|
||||||
|
&&OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN, \
|
||||||
&&OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN, \
|
&&OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN, \
|
||||||
&&OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN, \
|
&&OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN, \
|
||||||
&&OPCODE_AWAIT, \
|
&&OPCODE_AWAIT, \
|
||||||
@@ -1956,6 +1958,78 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||||||
}
|
}
|
||||||
DISPATCH_OPCODE;
|
DISPATCH_OPCODE;
|
||||||
|
|
||||||
|
OPCODE(OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN) {
|
||||||
|
LOAD_INSTRUCTION_ARGS
|
||||||
|
CHECK_SPACE(3 + instr_arg_count);
|
||||||
|
|
||||||
|
ip += instr_arg_count;
|
||||||
|
|
||||||
|
int argc = _code_ptr[ip + 1];
|
||||||
|
GD_ERR_BREAK(argc < 0);
|
||||||
|
|
||||||
|
GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count);
|
||||||
|
MethodBind *method = _methods_ptr[_code_ptr[ip + 2]];
|
||||||
|
|
||||||
|
Variant **argptrs = instruction_args;
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
uint64_t call_time = 0;
|
||||||
|
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
|
||||||
|
call_time = OS::get_singleton()->get_ticks_usec();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GET_INSTRUCTION_ARG(ret, argc);
|
||||||
|
method->validated_call(nullptr, (const Variant **)argptrs, ret);
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
|
||||||
|
uint64_t t_taken = OS::get_singleton()->get_ticks_usec() - call_time;
|
||||||
|
_profile_native_call(t_taken, method->get_name(), method->get_instance_class());
|
||||||
|
function_call_time += t_taken;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ip += 3;
|
||||||
|
}
|
||||||
|
DISPATCH_OPCODE;
|
||||||
|
|
||||||
|
OPCODE(OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN) {
|
||||||
|
LOAD_INSTRUCTION_ARGS
|
||||||
|
CHECK_SPACE(3 + instr_arg_count);
|
||||||
|
|
||||||
|
ip += instr_arg_count;
|
||||||
|
|
||||||
|
int argc = _code_ptr[ip + 1];
|
||||||
|
GD_ERR_BREAK(argc < 0);
|
||||||
|
|
||||||
|
GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count);
|
||||||
|
MethodBind *method = _methods_ptr[_code_ptr[ip + 2]];
|
||||||
|
|
||||||
|
Variant **argptrs = instruction_args;
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
uint64_t call_time = 0;
|
||||||
|
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
|
||||||
|
call_time = OS::get_singleton()->get_ticks_usec();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GET_INSTRUCTION_ARG(ret, argc);
|
||||||
|
VariantInternal::initialize(ret, Variant::NIL);
|
||||||
|
method->validated_call(nullptr, (const Variant **)argptrs, nullptr);
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
|
||||||
|
uint64_t t_taken = OS::get_singleton()->get_ticks_usec() - call_time;
|
||||||
|
_profile_native_call(t_taken, method->get_name(), method->get_instance_class());
|
||||||
|
function_call_time += t_taken;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ip += 3;
|
||||||
|
}
|
||||||
|
DISPATCH_OPCODE;
|
||||||
|
|
||||||
OPCODE(OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN) {
|
OPCODE(OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN) {
|
||||||
LOAD_INSTRUCTION_ARGS
|
LOAD_INSTRUCTION_ARGS
|
||||||
CHECK_SPACE(3 + instr_arg_count);
|
CHECK_SPACE(3 + instr_arg_count);
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
func test():
|
||||||
|
# Validated native static call with return value.
|
||||||
|
print(FileAccess.file_exists("some_file"))
|
||||||
|
|
||||||
|
# Validated native static call without return value.
|
||||||
|
Node.print_orphan_nodes()
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
GDTEST_OK
|
||||||
|
false
|
||||||
Reference in New Issue
Block a user