GDScript: Add faster instruction for validated constructor

Only for built-in types.
This commit is contained in:
George Marques 2020-11-18 11:37:08 -03:00
parent e0dca3c6b6
commit 5518e2a68e
No known key found for this signature in database
GPG Key ID: 046BD46A3201E43D
5 changed files with 112 additions and 3 deletions

View File

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

View File

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

View File

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

View File

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

View File

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