Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GDScript: Replace ptrcalls on MethodBind to validated calls #79893

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 18 additions & 59 deletions modules/gdscript/gdscript_byte_codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,6 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
}
function->_stack_size = RESERVED_STACK + max_locals + temporaries.size();
function->_instruction_args_size = instr_args_max;
function->_ptrcall_args_size = ptrcall_max;

#ifdef DEBUG_ENABLED
function->operator_names = operator_names;
Expand Down Expand Up @@ -1225,75 +1224,35 @@ void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target,
ct.cleanup();
}

void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {
#define CASE_TYPE(m_type) \
case Variant::m_type: \
append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_PTRCALL_##m_type, 2 + p_arguments.size()); \
break

bool is_ptrcall = true;

if (p_method->has_return()) {
MethodInfo info;
ClassDB::get_method_info(p_method->get_instance_class(), p_method->get_name(), &info);
switch (info.return_val.type) {
CASE_TYPE(BOOL);
CASE_TYPE(INT);
CASE_TYPE(FLOAT);
CASE_TYPE(STRING);
CASE_TYPE(VECTOR2);
CASE_TYPE(VECTOR2I);
CASE_TYPE(RECT2);
CASE_TYPE(RECT2I);
CASE_TYPE(VECTOR3);
CASE_TYPE(VECTOR3I);
CASE_TYPE(TRANSFORM2D);
CASE_TYPE(PLANE);
CASE_TYPE(AABB);
CASE_TYPE(BASIS);
CASE_TYPE(TRANSFORM3D);
CASE_TYPE(COLOR);
CASE_TYPE(STRING_NAME);
CASE_TYPE(NODE_PATH);
CASE_TYPE(RID);
CASE_TYPE(QUATERNION);
CASE_TYPE(OBJECT);
CASE_TYPE(CALLABLE);
CASE_TYPE(SIGNAL);
CASE_TYPE(DICTIONARY);
CASE_TYPE(ARRAY);
CASE_TYPE(PACKED_BYTE_ARRAY);
CASE_TYPE(PACKED_INT32_ARRAY);
CASE_TYPE(PACKED_INT64_ARRAY);
CASE_TYPE(PACKED_FLOAT32_ARRAY);
CASE_TYPE(PACKED_FLOAT64_ARRAY);
CASE_TYPE(PACKED_STRING_ARRAY);
CASE_TYPE(PACKED_VECTOR2_ARRAY);
CASE_TYPE(PACKED_VECTOR3_ARRAY);
CASE_TYPE(PACKED_COLOR_ARRAY);
default:
append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());
is_ptrcall = false;
break;
void GDScriptByteCodeGenerator::write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<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);
}
} else {
append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_PTRCALL_NO_RETURN, 2 + p_arguments.size());
}

GDScriptFunction::Opcode code = p_method->has_return() ? GDScriptFunction::OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN : GDScriptFunction::OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN;
append_opcode_and_argcount(code, 2 + p_arguments.size());

for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
append(p_base);
CallTarget ct = get_call_target(p_target);
append(ct.target);
append(p_arguments.size());
append(p_method);
ct.cleanup();
if (is_ptrcall) {
alloc_ptrcall(p_arguments.size());
}

#undef CASE_TYPE
}

void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {
Expand Down
9 changes: 1 addition & 8 deletions modules/gdscript/gdscript_byte_codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
int max_locals = 0;
int current_line = 0;
int instr_args_max = 0;
int ptrcall_max = 0;

#ifdef DEBUG_ENABLED
List<int> temp_stack;
Expand Down Expand Up @@ -346,12 +345,6 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return pos;
}

void alloc_ptrcall(int p_params) {
if (p_params >= ptrcall_max) {
ptrcall_max = p_params;
}
}

CallTarget get_call_target(const Address &p_target, Variant::Type p_type = Variant::NIL);

int address_of(const Address &p_address) {
Expand Down Expand Up @@ -519,7 +512,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
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_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_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;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
Expand Down
2 changes: 1 addition & 1 deletion modules/gdscript/gdscript_codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class GDScriptCodeGenerator {
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_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_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;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
Expand Down
20 changes: 10 additions & 10 deletions modules/gdscript/gdscript_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,13 @@ static bool _is_exact_type(const PropertyInfo &p_par_type, const GDScriptDataTyp
}
}

static bool _can_use_ptrcall(const MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {
static bool _can_use_validate_call(const MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {
if (p_method->is_vararg()) {
// ptrcall won't work with vararg methods.
// Validated call won't work with vararg methods.
return false;
}
if (p_method->get_argument_count() != p_arguments.size()) {
// ptrcall won't work with default arguments.
// Validated call won't work with default arguments.
return false;
}
MethodInfo info;
Expand Down Expand Up @@ -636,9 +636,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
self.mode = GDScriptCodeGenerator::Address::SELF;
MethodBind *method = ClassDB::get_method(codegen.script->native->get_name(), call->function_name);

if (_can_use_ptrcall(method, arguments)) {
// Exact arguments, use ptrcall.
gen->write_call_ptrcall(result, self, method, arguments);
if (_can_use_validate_call(method, arguments)) {
// Exact arguments, use validated call.
gen->write_call_method_bind_validated(result, self, method, arguments);
} else {
// Not exact arguments, but still can use method bind call.
gen->write_call_method_bind(result, self, method, arguments);
Expand Down Expand Up @@ -686,9 +686,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) {
MethodBind *method = ClassDB::get_method(class_name, call->function_name);
if (_can_use_ptrcall(method, arguments)) {
// Exact arguments, use ptrcall.
gen->write_call_ptrcall(result, base, method, arguments);
if (_can_use_validate_call(method, arguments)) {
// Exact arguments, use validated call.
gen->write_call_method_bind_validated(result, base, method, arguments);
} else {
// Not exact arguments, but still can use method bind call.
gen->write_call_method_bind(result, base, method, arguments);
Expand Down Expand Up @@ -733,7 +733,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(get_node->get_datatype(), codegen.script));

MethodBind *get_node_method = ClassDB::get_method("Node", "get_node");
gen->write_call_ptrcall(result, GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), get_node_method, args);
gen->write_call_method_bind_validated(result, GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), get_node_method, args);

return result;
} break;
Expand Down
82 changes: 21 additions & 61 deletions modules/gdscript/gdscript_disassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,10 +670,29 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {

incr += 4 + argc;
} break;
case OPCODE_CALL_PTRCALL_NO_RETURN: {

case OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN: {
int instr_var_args = _code_ptr[++ip];
text += "call method-bind validated (return) ";
MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
int argc = _code_ptr[ip + 1 + instr_var_args];
text += DADDR(2 + argc) + " = ";
text += DADDR(1 + argc) + ".";
text += method->get_name();
text += "(";
for (int i = 0; i < argc; i++) {
if (i > 0)
text += ", ";
text += DADDR(1 + i);
}
text += ")";
incr = 5 + argc;
} break;

text += "call-ptrcall (no return) ";
case OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN: {
int instr_var_args = _code_ptr[++ip];

text += "call method-bind validated (no return) ";

MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];

Expand All @@ -694,65 +713,6 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 5 + argc;
} break;

#define DISASSEMBLE_PTRCALL(m_type) \
case OPCODE_CALL_PTRCALL_##m_type: { \
int instr_var_args = _code_ptr[++ip]; \
text += "call-ptrcall (return "; \
text += #m_type; \
text += ") "; \
MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]]; \
int argc = _code_ptr[ip + 1 + instr_var_args]; \
text += DADDR(2 + argc) + " = "; \
text += DADDR(1 + argc) + "."; \
text += method->get_name(); \
text += "("; \
for (int i = 0; i < argc; i++) { \
if (i > 0) \
text += ", "; \
text += DADDR(1 + i); \
} \
text += ")"; \
incr = 5 + argc; \
} break

DISASSEMBLE_PTRCALL(BOOL);
DISASSEMBLE_PTRCALL(INT);
DISASSEMBLE_PTRCALL(FLOAT);
DISASSEMBLE_PTRCALL(STRING);
DISASSEMBLE_PTRCALL(VECTOR2);
DISASSEMBLE_PTRCALL(VECTOR2I);
DISASSEMBLE_PTRCALL(RECT2);
DISASSEMBLE_PTRCALL(RECT2I);
DISASSEMBLE_PTRCALL(VECTOR3);
DISASSEMBLE_PTRCALL(VECTOR3I);
DISASSEMBLE_PTRCALL(TRANSFORM2D);
DISASSEMBLE_PTRCALL(VECTOR4);
DISASSEMBLE_PTRCALL(VECTOR4I);
DISASSEMBLE_PTRCALL(PLANE);
DISASSEMBLE_PTRCALL(AABB);
DISASSEMBLE_PTRCALL(BASIS);
DISASSEMBLE_PTRCALL(TRANSFORM3D);
DISASSEMBLE_PTRCALL(PROJECTION);
DISASSEMBLE_PTRCALL(COLOR);
DISASSEMBLE_PTRCALL(STRING_NAME);
DISASSEMBLE_PTRCALL(NODE_PATH);
DISASSEMBLE_PTRCALL(RID);
DISASSEMBLE_PTRCALL(QUATERNION);
DISASSEMBLE_PTRCALL(OBJECT);
DISASSEMBLE_PTRCALL(CALLABLE);
DISASSEMBLE_PTRCALL(SIGNAL);
DISASSEMBLE_PTRCALL(DICTIONARY);
DISASSEMBLE_PTRCALL(ARRAY);
DISASSEMBLE_PTRCALL(PACKED_BYTE_ARRAY);
DISASSEMBLE_PTRCALL(PACKED_INT32_ARRAY);
DISASSEMBLE_PTRCALL(PACKED_INT64_ARRAY);
DISASSEMBLE_PTRCALL(PACKED_FLOAT32_ARRAY);
DISASSEMBLE_PTRCALL(PACKED_FLOAT64_ARRAY);
DISASSEMBLE_PTRCALL(PACKED_STRING_ARRAY);
DISASSEMBLE_PTRCALL(PACKED_VECTOR2_ARRAY);
DISASSEMBLE_PTRCALL(PACKED_VECTOR3_ARRAY);
DISASSEMBLE_PTRCALL(PACKED_COLOR_ARRAY);

case OPCODE_CALL_BUILTIN_TYPE_VALIDATED: {
int instr_var_args = _code_ptr[++ip];
int argc = _code_ptr[ip + 1 + instr_var_args];
Expand Down
42 changes: 2 additions & 40 deletions modules/gdscript/gdscript_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,45 +241,8 @@ class GDScriptFunction {
OPCODE_CALL_METHOD_BIND_RET,
OPCODE_CALL_BUILTIN_STATIC,
OPCODE_CALL_NATIVE_STATIC,
// ptrcall have one instruction per return type.
OPCODE_CALL_PTRCALL_NO_RETURN,
OPCODE_CALL_PTRCALL_BOOL,
OPCODE_CALL_PTRCALL_INT,
OPCODE_CALL_PTRCALL_FLOAT,
OPCODE_CALL_PTRCALL_STRING,
OPCODE_CALL_PTRCALL_VECTOR2,
OPCODE_CALL_PTRCALL_VECTOR2I,
OPCODE_CALL_PTRCALL_RECT2,
OPCODE_CALL_PTRCALL_RECT2I,
OPCODE_CALL_PTRCALL_VECTOR3,
OPCODE_CALL_PTRCALL_VECTOR3I,
OPCODE_CALL_PTRCALL_TRANSFORM2D,
OPCODE_CALL_PTRCALL_VECTOR4,
OPCODE_CALL_PTRCALL_VECTOR4I,
OPCODE_CALL_PTRCALL_PLANE,
OPCODE_CALL_PTRCALL_QUATERNION,
OPCODE_CALL_PTRCALL_AABB,
OPCODE_CALL_PTRCALL_BASIS,
OPCODE_CALL_PTRCALL_TRANSFORM3D,
OPCODE_CALL_PTRCALL_PROJECTION,
OPCODE_CALL_PTRCALL_COLOR,
OPCODE_CALL_PTRCALL_STRING_NAME,
OPCODE_CALL_PTRCALL_NODE_PATH,
OPCODE_CALL_PTRCALL_RID,
OPCODE_CALL_PTRCALL_OBJECT,
OPCODE_CALL_PTRCALL_CALLABLE,
OPCODE_CALL_PTRCALL_SIGNAL,
OPCODE_CALL_PTRCALL_DICTIONARY,
OPCODE_CALL_PTRCALL_ARRAY,
OPCODE_CALL_PTRCALL_PACKED_BYTE_ARRAY,
OPCODE_CALL_PTRCALL_PACKED_INT32_ARRAY,
OPCODE_CALL_PTRCALL_PACKED_INT64_ARRAY,
OPCODE_CALL_PTRCALL_PACKED_FLOAT32_ARRAY,
OPCODE_CALL_PTRCALL_PACKED_FLOAT64_ARRAY,
OPCODE_CALL_PTRCALL_PACKED_STRING_ARRAY,
OPCODE_CALL_PTRCALL_PACKED_VECTOR2_ARRAY,
OPCODE_CALL_PTRCALL_PACKED_VECTOR3_ARRAY,
OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY,
OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN,
OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN,
OPCODE_AWAIT,
OPCODE_AWAIT_RESUME,
OPCODE_CREATE_LAMBDA,
Expand Down Expand Up @@ -425,7 +388,6 @@ class GDScriptFunction {
int _argument_count = 0;
int _stack_size = 0;
int _instruction_args_size = 0;
int _ptrcall_args_size = 0;

SelfList<GDScriptFunction> function_list{ this };
mutable Variant nil;
Expand Down
Loading