Merge pull request #91192 from vnen/gdscript-validated-native-static-calls
GDScript: Perform validated calls with static methods
This commit is contained in:
commit
731ea17dd4
|
@ -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) {
|
||||
bool is_validated = false;
|
||||
|
||||
MethodBind *method = ClassDB::get_method(p_class, p_method);
|
||||
|
||||
if (!is_validated) {
|
||||
// Perform regular call.
|
||||
append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1);
|
||||
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();
|
||||
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) {
|
||||
|
|
|
@ -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_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_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_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;
|
||||
|
|
|
@ -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_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_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_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;
|
||||
|
|
|
@ -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") &&
|
||||
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.
|
||||
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 {
|
||||
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
|
||||
if (r_error) {
|
||||
|
|
|
@ -678,6 +678,50 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
|
|||
incr += 4 + argc;
|
||||
} 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: {
|
||||
int instr_var_args = _code_ptr[++ip];
|
||||
text += "call method-bind validated (return) ";
|
||||
|
|
|
@ -264,6 +264,8 @@ public:
|
|||
OPCODE_CALL_METHOD_BIND_RET,
|
||||
OPCODE_CALL_BUILTIN_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_NO_RETURN,
|
||||
OPCODE_AWAIT,
|
||||
|
|
|
@ -261,6 +261,8 @@ void (*type_init_function_table[])(Variant *) = {
|
|||
&&OPCODE_CALL_METHOD_BIND_RET, \
|
||||
&&OPCODE_CALL_BUILTIN_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_NO_RETURN, \
|
||||
&&OPCODE_AWAIT, \
|
||||
|
@ -1956,6 +1958,78 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
}
|
||||
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) {
|
||||
LOAD_INSTRUCTION_ARGS
|
||||
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
|
Loading…
Reference in New Issue