summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp47
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h15
-rw-r--r--modules/gdscript/gdscript_codegen.h1
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp21
-rw-r--r--modules/gdscript/gdscript_function.h4
-rw-r--r--modules/gdscript/gdscript_vm.cpp35
7 files changed, 125 insertions, 0 deletions
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 186ca1dfa2..2ee8e1a2fa 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -242,6 +242,18 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->_indexed_getters_ptr = nullptr;
}
+ if (builtin_method_map.size()) {
+ function->builtin_methods.resize(builtin_method_map.size());
+ function->_builtin_methods_ptr = function->builtin_methods.ptrw();
+ 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();
+ }
+ } else {
+ function->_builtin_methods_ptr = nullptr;
+ function->_builtin_methods_count = 0;
+ }
+
if (method_bind_map.size()) {
function->methods.resize(method_bind_map.size());
function->_methods_ptr = function->methods.ptrw();
@@ -647,6 +659,41 @@ void GDScriptByteCodeGenerator::write_call_builtin(const Address &p_target, GDSc
append(p_function);
}
+void GDScriptByteCodeGenerator::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) {
+ bool is_validated = false;
+
+ // Check if all types are correct.
+ if (Variant::is_builtin_method_vararg(p_type, p_method)) {
+ is_validated = true; // Vararg works fine with any argument, since they can be any type.
+ } else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) {
+ bool all_types_exact = true;
+ for (int i = 0; i < p_arguments.size(); i++) {
+ if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_builtin_method_argument_type(p_type, p_method, i))) {
+ all_types_exact = false;
+ break;
+ }
+ }
+
+ is_validated = all_types_exact;
+ }
+
+ if (!is_validated) {
+ // Perform regular call.
+ write_call(p_target, p_base, p_method, p_arguments);
+ return;
+ }
+
+ append(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size());
+
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_base);
+ append(p_target);
+ append(p_arguments.size());
+ append(Variant::get_validated_builtin_method(p_type, p_method));
+}
+
void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {
append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index 9b43adcd73..cced0ecabe 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -68,6 +68,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
Map<Variant::ValidatedKeyedGetter, int> keyed_getters_map;
Map<Variant::ValidatedIndexedSetter, int> indexed_setters_map;
Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map;
+ Map<Variant::ValidatedBuiltInMethod, int> builtin_method_map;
Map<MethodBind *, int> method_bind_map;
List<int> if_jmp_addrs; // List since this can be nested.
@@ -201,6 +202,15 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return pos;
}
+ int get_builtin_method_pos(const Variant::ValidatedBuiltInMethod p_method) {
+ if (builtin_method_map.has(p_method)) {
+ return builtin_method_map[p_method];
+ }
+ int pos = builtin_method_map.size();
+ builtin_method_map[p_method] = pos;
+ return pos;
+ }
+
int get_method_bind_pos(MethodBind *p_method) {
if (method_bind_map.has(p_method)) {
return method_bind_map[p_method];
@@ -298,6 +308,10 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
opcodes.push_back(get_indexed_getter_pos(p_indexed_getter));
}
+ void append(const Variant::ValidatedBuiltInMethod p_method) {
+ opcodes.push_back(get_builtin_method_pos(p_method));
+ }
+
void append(MethodBind *p_method) {
opcodes.push_back(get_method_bind_pos(p_method));
}
@@ -357,6 +371,7 @@ public:
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, 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_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_ptrcall(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;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index ff9bdb5f9e..2616a34719 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -126,6 +126,7 @@ public:
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, 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_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_ptrcall(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;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 8383e47dec..69fe6d27cc 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -522,6 +522,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} else {
gen->write_call(result, base, call->function_name, arguments);
}
+ } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) {
+ gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments);
} else {
gen->write_call(result, base, call->function_name, arguments);
}
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index bb76a14cfe..b6f9a6f647 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -572,6 +572,27 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
DISASSEMBLE_PTRCALL(PACKED_VECTOR3_ARRAY);
DISASSEMBLE_PTRCALL(PACKED_COLOR_ARRAY);
+ case OPCODE_CALL_BUILTIN_TYPE_VALIDATED: {
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+
+ text += "call-builtin-method validated ";
+
+ text += DADDR(2 + argc) + " = ";
+
+ text += DADDR(1) + ".";
+ text += "<unknown method>";
+
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 5 + argc;
+ } break;
case OPCODE_CALL_BUILT_IN: {
text += "call-built-in ";
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 1bc5ab6f64..794da38f8c 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -190,6 +190,7 @@ public:
OPCODE_CALL_RETURN,
OPCODE_CALL_ASYNC,
OPCODE_CALL_BUILT_IN,
+ OPCODE_CALL_BUILTIN_TYPE_VALIDATED,
OPCODE_CALL_SELF_BASE,
OPCODE_CALL_METHOD_BIND,
OPCODE_CALL_METHOD_BIND_RET,
@@ -300,6 +301,8 @@ private:
const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr;
int _indexed_getters_count = 0;
const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr;
+ int _builtin_methods_count = 0;
+ const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr;
int _methods_count = 0;
MethodBind **_methods_ptr = nullptr;
const int *_code_ptr = nullptr;
@@ -326,6 +329,7 @@ private:
Vector<Variant::ValidatedKeyedGetter> keyed_getters;
Vector<Variant::ValidatedIndexedSetter> indexed_setters;
Vector<Variant::ValidatedIndexedGetter> indexed_getters;
+ Vector<Variant::ValidatedBuiltInMethod> builtin_methods;
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 4772163b29..3a7d422f1d 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -219,6 +219,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CALL_RETURN, \
&&OPCODE_CALL_ASYNC, \
&&OPCODE_CALL_BUILT_IN, \
+ &&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
&&OPCODE_CALL_SELF_BASE, \
&&OPCODE_CALL_METHOD_BIND, \
&&OPCODE_CALL_METHOD_BIND_RET, \
@@ -1653,6 +1654,40 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_CALL_BUILTIN_TYPE_VALIDATED) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+ GD_ERR_BREAK(argc < 0);
+
+ GET_INSTRUCTION_ARG(base, argc);
+
+ GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _builtin_methods_count);
+ Variant::ValidatedBuiltInMethod method = _builtin_methods_ptr[_code_ptr[ip + 2]];
+ Variant **argptrs = instruction_args;
+
+#ifdef DEBUG_ENABLED
+ uint64_t call_time = 0;
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ call_time = OS::get_singleton()->get_ticks_usec();
+ }
+#endif
+
+ GET_INSTRUCTION_ARG(ret, argc + 1);
+ method(base, (const Variant **)argptrs, argc, ret);
+
+#ifdef DEBUG_ENABLED
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
+ }
+#endif
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_CALL_BUILT_IN) {
CHECK_SPACE(3 + instr_arg_count);