Quellcode durchsuchen

GDScript: Add faster instruction for validated constructor

Only for built-in types.
George Marques vor 4 Jahren
Ursprung
Commit
5518e2a68e

+ 53 - 1
modules/gdscript/gdscript_byte_codegen.cpp

@@ -244,7 +244,7 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
 
 	if (builtin_method_map.size()) {
 		function->builtin_methods.resize(builtin_method_map.size());
-		function->_builtin_methods_ptr = function->builtin_methods.ptrw();
+		function->_builtin_methods_ptr = function->builtin_methods.ptr();
 		function->_builtin_methods_count = builtin_method_map.size();
 		for (const Map<Variant::ValidatedBuiltInMethod, int>::Element *E = builtin_method_map.front(); E; E = E->next()) {
 			function->builtin_methods.write[E->get()] = E->key();
@@ -254,6 +254,18 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
 		function->_builtin_methods_count = 0;
 	}
 
+	if (constructors_map.size()) {
+		function->constructors.resize(constructors_map.size());
+		function->_constructors_ptr = function->constructors.ptr();
+		function->_constructors_count = constructors_map.size();
+		for (const Map<Variant::ValidatedConstructor, int>::Element *E = constructors_map.front(); E; E = E->next()) {
+			function->constructors.write[E->get()] = E->key();
+		}
+	} else {
+		function->_constructors_ptr = nullptr;
+		function->_constructors_count = 0;
+	}
+
 	if (method_bind_map.size()) {
 		function->methods.resize(method_bind_map.size());
 		function->_methods_ptr = function->methods.ptrw();
@@ -797,6 +809,46 @@ void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_targ
 }
 
 void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) {
+	// Try to find an appropriate constructor.
+	bool all_have_type = true;
+	Vector<Variant::Type> arg_types;
+	for (int i = 0; i < p_arguments.size(); i++) {
+		if (!HAS_BUILTIN_TYPE(p_arguments[i])) {
+			all_have_type = false;
+			break;
+		}
+		arg_types.push_back(p_arguments[i].type.builtin_type);
+	}
+	if (all_have_type) {
+		int valid_constructor = -1;
+		for (int i = 0; i < Variant::get_constructor_count(p_type); i++) {
+			if (Variant::get_constructor_argument_count(p_type, i) != p_arguments.size()) {
+				continue;
+			}
+			int types_correct = true;
+			for (int j = 0; j < arg_types.size(); j++) {
+				if (arg_types[j] != Variant::get_constructor_argument_type(p_type, i, j)) {
+					types_correct = false;
+					break;
+				}
+			}
+			if (types_correct) {
+				valid_constructor = i;
+				break;
+			}
+		}
+		if (valid_constructor >= 0) {
+			append(GDScriptFunction::OPCODE_CONSTRUCT_VALIDATED, 1 + p_arguments.size());
+			for (int i = 0; i < p_arguments.size(); i++) {
+				append(p_arguments[i]);
+			}
+			append(p_target);
+			append(p_arguments.size());
+			append(Variant::get_validated_constructor(p_type, valid_constructor));
+			return;
+		}
+	}
+
 	append(GDScriptFunction::OPCODE_CONSTRUCT, 1 + p_arguments.size());
 	for (int i = 0; i < p_arguments.size(); i++) {
 		append(p_arguments[i]);

+ 14 - 0
modules/gdscript/gdscript_byte_codegen.h

@@ -69,6 +69,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
 	Map<Variant::ValidatedIndexedSetter, int> indexed_setters_map;
 	Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map;
 	Map<Variant::ValidatedBuiltInMethod, int> builtin_method_map;
+	Map<Variant::ValidatedConstructor, int> constructors_map;
 	Map<MethodBind *, int> method_bind_map;
 
 	List<int> if_jmp_addrs; // List since this can be nested.
@@ -211,6 +212,15 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
 		return pos;
 	}
 
+	int get_constructor_pos(const Variant::ValidatedConstructor p_constructor) {
+		if (constructors_map.has(p_constructor)) {
+			return constructors_map[p_constructor];
+		}
+		int pos = constructors_map.size();
+		constructors_map[p_constructor] = pos;
+		return pos;
+	}
+
 	int get_method_bind_pos(MethodBind *p_method) {
 		if (method_bind_map.has(p_method)) {
 			return method_bind_map[p_method];
@@ -312,6 +322,10 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
 		opcodes.push_back(get_builtin_method_pos(p_method));
 	}
 
+	void append(const Variant::ValidatedConstructor p_constructor) {
+		opcodes.push_back(get_constructor_pos(p_constructor));
+	}
+
 	void append(MethodBind *p_method) {
 		opcodes.push_back(get_method_bind_pos(p_method));
 	}

+ 18 - 1
modules/gdscript/gdscript_disassembler.cpp

@@ -384,7 +384,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
 			} break;
 			case OPCODE_CONSTRUCT: {
 				Variant::Type t = Variant::Type(_code_ptr[ip + 3 + instr_var_args]);
-				int argc = _code_ptr[ip + 2 + instr_var_args];
+				int argc = _code_ptr[ip + 1 + instr_var_args];
 
 				text += "construct ";
 				text += DADDR(1 + argc);
@@ -400,6 +400,23 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
 
 				incr = 3 + instr_var_args;
 			} break;
+			case OPCODE_CONSTRUCT_VALIDATED: {
+				int argc = _code_ptr[ip + 1 + instr_var_args];
+
+				text += "construct validated ";
+				text += DADDR(1 + argc);
+				text += " = ";
+
+				text += "<unkown type>(";
+				for (int i = 0; i < argc; i++) {
+					if (i > 0)
+						text += ", ";
+					text += DADDR(i + 1);
+				}
+				text += ")";
+
+				incr = 3 + instr_var_args;
+			} break;
 			case OPCODE_CONSTRUCT_ARRAY: {
 				int argc = _code_ptr[ip + 1 + instr_var_args];
 				text += " make_array ";

+ 5 - 1
modules/gdscript/gdscript_function.h

@@ -183,7 +183,8 @@ public:
 		OPCODE_CAST_TO_BUILTIN,
 		OPCODE_CAST_TO_NATIVE,
 		OPCODE_CAST_TO_SCRIPT,
-		OPCODE_CONSTRUCT, //only for basic types!!
+		OPCODE_CONSTRUCT, // Only for basic types!
+		OPCODE_CONSTRUCT_VALIDATED, // Only for basic types!
 		OPCODE_CONSTRUCT_ARRAY,
 		OPCODE_CONSTRUCT_DICTIONARY,
 		OPCODE_CALL,
@@ -341,6 +342,8 @@ private:
 	const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr;
 	int _builtin_methods_count = 0;
 	const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr;
+	int _constructors_count = 0;
+	const Variant::ValidatedConstructor *_constructors_ptr = nullptr;
 	int _methods_count = 0;
 	MethodBind **_methods_ptr = nullptr;
 	const int *_code_ptr = nullptr;
@@ -368,6 +371,7 @@ private:
 	Vector<Variant::ValidatedIndexedSetter> indexed_setters;
 	Vector<Variant::ValidatedIndexedGetter> indexed_getters;
 	Vector<Variant::ValidatedBuiltInMethod> builtin_methods;
+	Vector<Variant::ValidatedConstructor> constructors;
 	Vector<MethodBind *> methods;
 	Vector<int> code;
 	Vector<GDScriptDataType> argument_types;

+ 22 - 0
modules/gdscript/gdscript_vm.cpp

@@ -214,6 +214,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
 		&&OPCODE_CAST_TO_NATIVE,                     \
 		&&OPCODE_CAST_TO_SCRIPT,                     \
 		&&OPCODE_CONSTRUCT,                          \
+		&&OPCODE_CONSTRUCT_VALIDATED,                \
 		&&OPCODE_CONSTRUCT_ARRAY,                    \
 		&&OPCODE_CONSTRUCT_DICTIONARY,               \
 		&&OPCODE_CALL,                               \
@@ -1276,6 +1277,27 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 			}
 			DISPATCH_OPCODE;
 
+			OPCODE(OPCODE_CONSTRUCT_VALIDATED) {
+				CHECK_SPACE(2 + instr_arg_count);
+
+				ip += instr_arg_count;
+
+				int argc = _code_ptr[ip + 1];
+
+				int constructor_idx = _code_ptr[ip + 2];
+				GD_ERR_BREAK(constructor_idx < 0 || constructor_idx >= _constructors_count);
+				Variant::ValidatedConstructor constructor = _constructors_ptr[constructor_idx];
+
+				Variant **argptrs = instruction_args;
+
+				GET_INSTRUCTION_ARG(dst, argc);
+
+				constructor(*dst, (const Variant **)argptrs);
+
+				ip += 3;
+			}
+			DISPATCH_OPCODE;
+
 			OPCODE(OPCODE_CONSTRUCT_ARRAY) {
 				CHECK_SPACE(1 + instr_arg_count);
 				ip += instr_arg_count;