Browse Source

Merge pull request #91192 from vnen/gdscript-validated-native-static-calls

GDScript: Perform validated calls with static methods
Rémi Verschelde 1 year ago
parent
commit
731ea17dd4

+ 39 - 13
modules/gdscript/gdscript_byte_codegen.cpp

@@ -1196,23 +1196,49 @@ 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++) {
-			append(p_arguments[i]);
+	// 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++) {
+		append(p_arguments[i]);
+	}
+	CallTarget ct = get_call_target(p_target);
+	append(ct.target);
+	append(method);
+	append(p_arguments.size());
+	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);
 		}
-		CallTarget ct = get_call_target(p_target);
-		append(ct.target);
-		append(method);
-		append(p_arguments.size());
-		ct.cleanup();
-		return;
 	}
+
+	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) {

+ 1 - 0
modules/gdscript/gdscript_byte_codegen.h

@@ -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;

+ 1 - 0
modules/gdscript/gdscript_codegen.h

@@ -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;

+ 9 - 1
modules/gdscript/gdscript_compiler.cpp

@@ -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) {

+ 44 - 0
modules/gdscript/gdscript_disassembler.cpp

@@ -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) ";

+ 2 - 0
modules/gdscript/gdscript_function.h

@@ -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,

+ 224 - 150
modules/gdscript/gdscript_vm.cpp

@@ -211,156 +211,158 @@ void (*type_init_function_table[])(Variant *) = {
 };
 
 #if defined(__GNUC__)
-#define OPCODES_TABLE                                  \
-	static const void *switch_table_ops[] = {          \
-		&&OPCODE_OPERATOR,                             \
-		&&OPCODE_OPERATOR_VALIDATED,                   \
-		&&OPCODE_TYPE_TEST_BUILTIN,                    \
-		&&OPCODE_TYPE_TEST_ARRAY,                      \
-		&&OPCODE_TYPE_TEST_NATIVE,                     \
-		&&OPCODE_TYPE_TEST_SCRIPT,                     \
-		&&OPCODE_SET_KEYED,                            \
-		&&OPCODE_SET_KEYED_VALIDATED,                  \
-		&&OPCODE_SET_INDEXED_VALIDATED,                \
-		&&OPCODE_GET_KEYED,                            \
-		&&OPCODE_GET_KEYED_VALIDATED,                  \
-		&&OPCODE_GET_INDEXED_VALIDATED,                \
-		&&OPCODE_SET_NAMED,                            \
-		&&OPCODE_SET_NAMED_VALIDATED,                  \
-		&&OPCODE_GET_NAMED,                            \
-		&&OPCODE_GET_NAMED_VALIDATED,                  \
-		&&OPCODE_SET_MEMBER,                           \
-		&&OPCODE_GET_MEMBER,                           \
-		&&OPCODE_SET_STATIC_VARIABLE,                  \
-		&&OPCODE_GET_STATIC_VARIABLE,                  \
-		&&OPCODE_ASSIGN,                               \
-		&&OPCODE_ASSIGN_NULL,                          \
-		&&OPCODE_ASSIGN_TRUE,                          \
-		&&OPCODE_ASSIGN_FALSE,                         \
-		&&OPCODE_ASSIGN_TYPED_BUILTIN,                 \
-		&&OPCODE_ASSIGN_TYPED_ARRAY,                   \
-		&&OPCODE_ASSIGN_TYPED_NATIVE,                  \
-		&&OPCODE_ASSIGN_TYPED_SCRIPT,                  \
-		&&OPCODE_CAST_TO_BUILTIN,                      \
-		&&OPCODE_CAST_TO_NATIVE,                       \
-		&&OPCODE_CAST_TO_SCRIPT,                       \
-		&&OPCODE_CONSTRUCT,                            \
-		&&OPCODE_CONSTRUCT_VALIDATED,                  \
-		&&OPCODE_CONSTRUCT_ARRAY,                      \
-		&&OPCODE_CONSTRUCT_TYPED_ARRAY,                \
-		&&OPCODE_CONSTRUCT_DICTIONARY,                 \
-		&&OPCODE_CALL,                                 \
-		&&OPCODE_CALL_RETURN,                          \
-		&&OPCODE_CALL_ASYNC,                           \
-		&&OPCODE_CALL_UTILITY,                         \
-		&&OPCODE_CALL_UTILITY_VALIDATED,               \
-		&&OPCODE_CALL_GDSCRIPT_UTILITY,                \
-		&&OPCODE_CALL_BUILTIN_TYPE_VALIDATED,          \
-		&&OPCODE_CALL_SELF_BASE,                       \
-		&&OPCODE_CALL_METHOD_BIND,                     \
-		&&OPCODE_CALL_METHOD_BIND_RET,                 \
-		&&OPCODE_CALL_BUILTIN_STATIC,                  \
-		&&OPCODE_CALL_NATIVE_STATIC,                   \
-		&&OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN,    \
-		&&OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN, \
-		&&OPCODE_AWAIT,                                \
-		&&OPCODE_AWAIT_RESUME,                         \
-		&&OPCODE_CREATE_LAMBDA,                        \
-		&&OPCODE_CREATE_SELF_LAMBDA,                   \
-		&&OPCODE_JUMP,                                 \
-		&&OPCODE_JUMP_IF,                              \
-		&&OPCODE_JUMP_IF_NOT,                          \
-		&&OPCODE_JUMP_TO_DEF_ARGUMENT,                 \
-		&&OPCODE_JUMP_IF_SHARED,                       \
-		&&OPCODE_RETURN,                               \
-		&&OPCODE_RETURN_TYPED_BUILTIN,                 \
-		&&OPCODE_RETURN_TYPED_ARRAY,                   \
-		&&OPCODE_RETURN_TYPED_NATIVE,                  \
-		&&OPCODE_RETURN_TYPED_SCRIPT,                  \
-		&&OPCODE_ITERATE_BEGIN,                        \
-		&&OPCODE_ITERATE_BEGIN_INT,                    \
-		&&OPCODE_ITERATE_BEGIN_FLOAT,                  \
-		&&OPCODE_ITERATE_BEGIN_VECTOR2,                \
-		&&OPCODE_ITERATE_BEGIN_VECTOR2I,               \
-		&&OPCODE_ITERATE_BEGIN_VECTOR3,                \
-		&&OPCODE_ITERATE_BEGIN_VECTOR3I,               \
-		&&OPCODE_ITERATE_BEGIN_STRING,                 \
-		&&OPCODE_ITERATE_BEGIN_DICTIONARY,             \
-		&&OPCODE_ITERATE_BEGIN_ARRAY,                  \
-		&&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY,      \
-		&&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY,     \
-		&&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY,     \
-		&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY,   \
-		&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY,   \
-		&&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY,    \
-		&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY,   \
-		&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY,   \
-		&&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY,     \
-		&&OPCODE_ITERATE_BEGIN_OBJECT,                 \
-		&&OPCODE_ITERATE,                              \
-		&&OPCODE_ITERATE_INT,                          \
-		&&OPCODE_ITERATE_FLOAT,                        \
-		&&OPCODE_ITERATE_VECTOR2,                      \
-		&&OPCODE_ITERATE_VECTOR2I,                     \
-		&&OPCODE_ITERATE_VECTOR3,                      \
-		&&OPCODE_ITERATE_VECTOR3I,                     \
-		&&OPCODE_ITERATE_STRING,                       \
-		&&OPCODE_ITERATE_DICTIONARY,                   \
-		&&OPCODE_ITERATE_ARRAY,                        \
-		&&OPCODE_ITERATE_PACKED_BYTE_ARRAY,            \
-		&&OPCODE_ITERATE_PACKED_INT32_ARRAY,           \
-		&&OPCODE_ITERATE_PACKED_INT64_ARRAY,           \
-		&&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY,         \
-		&&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY,         \
-		&&OPCODE_ITERATE_PACKED_STRING_ARRAY,          \
-		&&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY,         \
-		&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY,         \
-		&&OPCODE_ITERATE_PACKED_COLOR_ARRAY,           \
-		&&OPCODE_ITERATE_OBJECT,                       \
-		&&OPCODE_STORE_GLOBAL,                         \
-		&&OPCODE_STORE_NAMED_GLOBAL,                   \
-		&&OPCODE_TYPE_ADJUST_BOOL,                     \
-		&&OPCODE_TYPE_ADJUST_INT,                      \
-		&&OPCODE_TYPE_ADJUST_FLOAT,                    \
-		&&OPCODE_TYPE_ADJUST_STRING,                   \
-		&&OPCODE_TYPE_ADJUST_VECTOR2,                  \
-		&&OPCODE_TYPE_ADJUST_VECTOR2I,                 \
-		&&OPCODE_TYPE_ADJUST_RECT2,                    \
-		&&OPCODE_TYPE_ADJUST_RECT2I,                   \
-		&&OPCODE_TYPE_ADJUST_VECTOR3,                  \
-		&&OPCODE_TYPE_ADJUST_VECTOR3I,                 \
-		&&OPCODE_TYPE_ADJUST_TRANSFORM2D,              \
-		&&OPCODE_TYPE_ADJUST_VECTOR4,                  \
-		&&OPCODE_TYPE_ADJUST_VECTOR4I,                 \
-		&&OPCODE_TYPE_ADJUST_PLANE,                    \
-		&&OPCODE_TYPE_ADJUST_QUATERNION,               \
-		&&OPCODE_TYPE_ADJUST_AABB,                     \
-		&&OPCODE_TYPE_ADJUST_BASIS,                    \
-		&&OPCODE_TYPE_ADJUST_TRANSFORM3D,              \
-		&&OPCODE_TYPE_ADJUST_PROJECTION,               \
-		&&OPCODE_TYPE_ADJUST_COLOR,                    \
-		&&OPCODE_TYPE_ADJUST_STRING_NAME,              \
-		&&OPCODE_TYPE_ADJUST_NODE_PATH,                \
-		&&OPCODE_TYPE_ADJUST_RID,                      \
-		&&OPCODE_TYPE_ADJUST_OBJECT,                   \
-		&&OPCODE_TYPE_ADJUST_CALLABLE,                 \
-		&&OPCODE_TYPE_ADJUST_SIGNAL,                   \
-		&&OPCODE_TYPE_ADJUST_DICTIONARY,               \
-		&&OPCODE_TYPE_ADJUST_ARRAY,                    \
-		&&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY,        \
-		&&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY,       \
-		&&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY,       \
-		&&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY,     \
-		&&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY,     \
-		&&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY,      \
-		&&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY,     \
-		&&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY,     \
-		&&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY,       \
-		&&OPCODE_ASSERT,                               \
-		&&OPCODE_BREAKPOINT,                           \
-		&&OPCODE_LINE,                                 \
-		&&OPCODE_END                                   \
-	};                                                 \
+#define OPCODES_TABLE                                    \
+	static const void *switch_table_ops[] = {            \
+		&&OPCODE_OPERATOR,                               \
+		&&OPCODE_OPERATOR_VALIDATED,                     \
+		&&OPCODE_TYPE_TEST_BUILTIN,                      \
+		&&OPCODE_TYPE_TEST_ARRAY,                        \
+		&&OPCODE_TYPE_TEST_NATIVE,                       \
+		&&OPCODE_TYPE_TEST_SCRIPT,                       \
+		&&OPCODE_SET_KEYED,                              \
+		&&OPCODE_SET_KEYED_VALIDATED,                    \
+		&&OPCODE_SET_INDEXED_VALIDATED,                  \
+		&&OPCODE_GET_KEYED,                              \
+		&&OPCODE_GET_KEYED_VALIDATED,                    \
+		&&OPCODE_GET_INDEXED_VALIDATED,                  \
+		&&OPCODE_SET_NAMED,                              \
+		&&OPCODE_SET_NAMED_VALIDATED,                    \
+		&&OPCODE_GET_NAMED,                              \
+		&&OPCODE_GET_NAMED_VALIDATED,                    \
+		&&OPCODE_SET_MEMBER,                             \
+		&&OPCODE_GET_MEMBER,                             \
+		&&OPCODE_SET_STATIC_VARIABLE,                    \
+		&&OPCODE_GET_STATIC_VARIABLE,                    \
+		&&OPCODE_ASSIGN,                                 \
+		&&OPCODE_ASSIGN_NULL,                            \
+		&&OPCODE_ASSIGN_TRUE,                            \
+		&&OPCODE_ASSIGN_FALSE,                           \
+		&&OPCODE_ASSIGN_TYPED_BUILTIN,                   \
+		&&OPCODE_ASSIGN_TYPED_ARRAY,                     \
+		&&OPCODE_ASSIGN_TYPED_NATIVE,                    \
+		&&OPCODE_ASSIGN_TYPED_SCRIPT,                    \
+		&&OPCODE_CAST_TO_BUILTIN,                        \
+		&&OPCODE_CAST_TO_NATIVE,                         \
+		&&OPCODE_CAST_TO_SCRIPT,                         \
+		&&OPCODE_CONSTRUCT,                              \
+		&&OPCODE_CONSTRUCT_VALIDATED,                    \
+		&&OPCODE_CONSTRUCT_ARRAY,                        \
+		&&OPCODE_CONSTRUCT_TYPED_ARRAY,                  \
+		&&OPCODE_CONSTRUCT_DICTIONARY,                   \
+		&&OPCODE_CALL,                                   \
+		&&OPCODE_CALL_RETURN,                            \
+		&&OPCODE_CALL_ASYNC,                             \
+		&&OPCODE_CALL_UTILITY,                           \
+		&&OPCODE_CALL_UTILITY_VALIDATED,                 \
+		&&OPCODE_CALL_GDSCRIPT_UTILITY,                  \
+		&&OPCODE_CALL_BUILTIN_TYPE_VALIDATED,            \
+		&&OPCODE_CALL_SELF_BASE,                         \
+		&&OPCODE_CALL_METHOD_BIND,                       \
+		&&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,                                  \
+		&&OPCODE_AWAIT_RESUME,                           \
+		&&OPCODE_CREATE_LAMBDA,                          \
+		&&OPCODE_CREATE_SELF_LAMBDA,                     \
+		&&OPCODE_JUMP,                                   \
+		&&OPCODE_JUMP_IF,                                \
+		&&OPCODE_JUMP_IF_NOT,                            \
+		&&OPCODE_JUMP_TO_DEF_ARGUMENT,                   \
+		&&OPCODE_JUMP_IF_SHARED,                         \
+		&&OPCODE_RETURN,                                 \
+		&&OPCODE_RETURN_TYPED_BUILTIN,                   \
+		&&OPCODE_RETURN_TYPED_ARRAY,                     \
+		&&OPCODE_RETURN_TYPED_NATIVE,                    \
+		&&OPCODE_RETURN_TYPED_SCRIPT,                    \
+		&&OPCODE_ITERATE_BEGIN,                          \
+		&&OPCODE_ITERATE_BEGIN_INT,                      \
+		&&OPCODE_ITERATE_BEGIN_FLOAT,                    \
+		&&OPCODE_ITERATE_BEGIN_VECTOR2,                  \
+		&&OPCODE_ITERATE_BEGIN_VECTOR2I,                 \
+		&&OPCODE_ITERATE_BEGIN_VECTOR3,                  \
+		&&OPCODE_ITERATE_BEGIN_VECTOR3I,                 \
+		&&OPCODE_ITERATE_BEGIN_STRING,                   \
+		&&OPCODE_ITERATE_BEGIN_DICTIONARY,               \
+		&&OPCODE_ITERATE_BEGIN_ARRAY,                    \
+		&&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY,        \
+		&&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY,       \
+		&&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY,       \
+		&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY,     \
+		&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY,     \
+		&&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY,      \
+		&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY,     \
+		&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY,     \
+		&&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY,       \
+		&&OPCODE_ITERATE_BEGIN_OBJECT,                   \
+		&&OPCODE_ITERATE,                                \
+		&&OPCODE_ITERATE_INT,                            \
+		&&OPCODE_ITERATE_FLOAT,                          \
+		&&OPCODE_ITERATE_VECTOR2,                        \
+		&&OPCODE_ITERATE_VECTOR2I,                       \
+		&&OPCODE_ITERATE_VECTOR3,                        \
+		&&OPCODE_ITERATE_VECTOR3I,                       \
+		&&OPCODE_ITERATE_STRING,                         \
+		&&OPCODE_ITERATE_DICTIONARY,                     \
+		&&OPCODE_ITERATE_ARRAY,                          \
+		&&OPCODE_ITERATE_PACKED_BYTE_ARRAY,              \
+		&&OPCODE_ITERATE_PACKED_INT32_ARRAY,             \
+		&&OPCODE_ITERATE_PACKED_INT64_ARRAY,             \
+		&&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY,           \
+		&&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY,           \
+		&&OPCODE_ITERATE_PACKED_STRING_ARRAY,            \
+		&&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY,           \
+		&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY,           \
+		&&OPCODE_ITERATE_PACKED_COLOR_ARRAY,             \
+		&&OPCODE_ITERATE_OBJECT,                         \
+		&&OPCODE_STORE_GLOBAL,                           \
+		&&OPCODE_STORE_NAMED_GLOBAL,                     \
+		&&OPCODE_TYPE_ADJUST_BOOL,                       \
+		&&OPCODE_TYPE_ADJUST_INT,                        \
+		&&OPCODE_TYPE_ADJUST_FLOAT,                      \
+		&&OPCODE_TYPE_ADJUST_STRING,                     \
+		&&OPCODE_TYPE_ADJUST_VECTOR2,                    \
+		&&OPCODE_TYPE_ADJUST_VECTOR2I,                   \
+		&&OPCODE_TYPE_ADJUST_RECT2,                      \
+		&&OPCODE_TYPE_ADJUST_RECT2I,                     \
+		&&OPCODE_TYPE_ADJUST_VECTOR3,                    \
+		&&OPCODE_TYPE_ADJUST_VECTOR3I,                   \
+		&&OPCODE_TYPE_ADJUST_TRANSFORM2D,                \
+		&&OPCODE_TYPE_ADJUST_VECTOR4,                    \
+		&&OPCODE_TYPE_ADJUST_VECTOR4I,                   \
+		&&OPCODE_TYPE_ADJUST_PLANE,                      \
+		&&OPCODE_TYPE_ADJUST_QUATERNION,                 \
+		&&OPCODE_TYPE_ADJUST_AABB,                       \
+		&&OPCODE_TYPE_ADJUST_BASIS,                      \
+		&&OPCODE_TYPE_ADJUST_TRANSFORM3D,                \
+		&&OPCODE_TYPE_ADJUST_PROJECTION,                 \
+		&&OPCODE_TYPE_ADJUST_COLOR,                      \
+		&&OPCODE_TYPE_ADJUST_STRING_NAME,                \
+		&&OPCODE_TYPE_ADJUST_NODE_PATH,                  \
+		&&OPCODE_TYPE_ADJUST_RID,                        \
+		&&OPCODE_TYPE_ADJUST_OBJECT,                     \
+		&&OPCODE_TYPE_ADJUST_CALLABLE,                   \
+		&&OPCODE_TYPE_ADJUST_SIGNAL,                     \
+		&&OPCODE_TYPE_ADJUST_DICTIONARY,                 \
+		&&OPCODE_TYPE_ADJUST_ARRAY,                      \
+		&&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY,          \
+		&&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY,         \
+		&&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY,         \
+		&&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY,       \
+		&&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY,       \
+		&&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY,        \
+		&&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY,       \
+		&&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY,       \
+		&&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY,         \
+		&&OPCODE_ASSERT,                                 \
+		&&OPCODE_BREAKPOINT,                             \
+		&&OPCODE_LINE,                                   \
+		&&OPCODE_END                                     \
+	};                                                   \
 	static_assert((sizeof(switch_table_ops) / sizeof(switch_table_ops[0]) == (OPCODE_END + 1)), "Opcodes in jump table aren't the same as opcodes in enum.");
 
 #define OPCODE(m_op) \
@@ -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);

+ 7 - 0
modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.gd

@@ -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()
+

+ 2 - 0
modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.out

@@ -0,0 +1,2 @@
+GDTEST_OK
+false