summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp54
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h14
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp19
-rw-r--r--modules/gdscript/gdscript_function.h6
-rw-r--r--modules/gdscript/gdscript_vm.cpp22
5 files changed, 112 insertions, 3 deletions
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 5772f8bce3..5f1c738207 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/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]);
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index cced0ecabe..a546920fb2 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/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));
}
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 9f224108a7..c918251772 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/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 ";
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 3fb63f1297..bb5cc1284d 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/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;
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 04cd41ed6b..7c8bfcd944 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/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;