GDScript: Add faster call instructions for native methods
This commit is contained in:
parent
5aeb390cd7
commit
d8b22097f2
|
@ -242,11 +242,24 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
|
|||
function->_indexed_getters_ptr = nullptr;
|
||||
}
|
||||
|
||||
if (method_bind_map.size()) {
|
||||
function->methods.resize(method_bind_map.size());
|
||||
function->_methods_ptr = function->methods.ptrw();
|
||||
function->_methods_count = method_bind_map.size();
|
||||
for (const Map<MethodBind *, int>::Element *E = method_bind_map.front(); E; E = E->next()) {
|
||||
function->methods.write[E->get()] = E->key();
|
||||
}
|
||||
} else {
|
||||
function->_methods_ptr = nullptr;
|
||||
function->_methods_count = 0;
|
||||
}
|
||||
|
||||
if (debug_stack) {
|
||||
function->stack_debug = stack_debug;
|
||||
}
|
||||
function->_stack_size = stack_max;
|
||||
function->_instruction_args_size = instr_args_max;
|
||||
function->_ptrcall_args_size = ptrcall_max;
|
||||
|
||||
ended = true;
|
||||
return function;
|
||||
|
@ -634,26 +647,84 @@ void GDScriptByteCodeGenerator::write_call_builtin(const Address &p_target, GDSc
|
|||
append(p_function);
|
||||
}
|
||||
|
||||
void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) {
|
||||
append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());
|
||||
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++) {
|
||||
append(p_arguments[i]);
|
||||
}
|
||||
append(p_base);
|
||||
append(p_target);
|
||||
append(p_arguments.size());
|
||||
append(p_method->get_name());
|
||||
append(p_method);
|
||||
}
|
||||
|
||||
void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) {
|
||||
append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());
|
||||
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(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(TRANSFORM);
|
||||
CASE_TYPE(COLOR);
|
||||
CASE_TYPE(STRING_NAME);
|
||||
CASE_TYPE(NODE_PATH);
|
||||
CASE_TYPE(RID);
|
||||
CASE_TYPE(QUAT);
|
||||
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(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());
|
||||
is_ptrcall = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
append(GDScriptFunction::OPCODE_CALL_PTRCALL_NO_RETURN, 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(p_method->get_name());
|
||||
append(p_method);
|
||||
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) {
|
||||
|
|
|
@ -54,6 +54,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
|
|||
int current_line = 0;
|
||||
int stack_max = 0;
|
||||
int instr_args_max = 0;
|
||||
int ptrcall_max = 0;
|
||||
|
||||
HashMap<Variant, int, VariantHasher, VariantComparator> constant_map;
|
||||
Map<StringName, int> name_map;
|
||||
|
@ -67,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<MethodBind *, int> method_bind_map;
|
||||
|
||||
List<int> if_jmp_addrs; // List since this can be nested.
|
||||
List<int> for_jmp_addrs;
|
||||
|
@ -199,6 +201,15 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
|
|||
return pos;
|
||||
}
|
||||
|
||||
int get_method_bind_pos(MethodBind *p_method) {
|
||||
if (method_bind_map.has(p_method)) {
|
||||
return method_bind_map[p_method];
|
||||
}
|
||||
int pos = method_bind_map.size();
|
||||
method_bind_map[p_method] = pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
void alloc_stack(int p_level) {
|
||||
if (p_level >= stack_max)
|
||||
stack_max = p_level + 1;
|
||||
|
@ -210,6 +221,11 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
|
|||
return top;
|
||||
}
|
||||
|
||||
void alloc_ptrcall(int p_params) {
|
||||
if (p_params >= ptrcall_max)
|
||||
ptrcall_max = p_params;
|
||||
}
|
||||
|
||||
int address_of(const Address &p_address) {
|
||||
switch (p_address.mode) {
|
||||
case Address::SELF:
|
||||
|
@ -282,6 +298,10 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
|
|||
opcodes.push_back(get_indexed_getter_pos(p_indexed_getter));
|
||||
}
|
||||
|
||||
void append(MethodBind *p_method) {
|
||||
opcodes.push_back(get_method_bind_pos(p_method));
|
||||
}
|
||||
|
||||
void patch_jump(int p_address) {
|
||||
opcodes.write[p_address] = opcodes.size();
|
||||
}
|
||||
|
@ -337,8 +357,8 @@ 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_method_bind(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) override;
|
||||
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, const MethodBind *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;
|
||||
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;
|
||||
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) override;
|
||||
|
|
|
@ -126,8 +126,8 @@ 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_method_bind(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
|
||||
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, const MethodBind *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;
|
||||
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;
|
||||
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) = 0;
|
||||
|
|
|
@ -158,6 +158,48 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
|
|||
return result;
|
||||
}
|
||||
|
||||
static bool _is_exact_type(const PropertyInfo &p_par_type, const GDScriptDataType &p_arg_type) {
|
||||
if (!p_arg_type.has_type) {
|
||||
return false;
|
||||
}
|
||||
if (p_par_type.type == Variant::NIL) {
|
||||
return false;
|
||||
}
|
||||
if (p_par_type.type == Variant::OBJECT) {
|
||||
if (p_arg_type.kind == GDScriptDataType::BUILTIN) {
|
||||
return false;
|
||||
}
|
||||
StringName class_name;
|
||||
if (p_arg_type.kind == GDScriptDataType::NATIVE) {
|
||||
class_name = p_arg_type.native_type;
|
||||
} else {
|
||||
class_name = p_arg_type.native_type == StringName() ? p_arg_type.script_type->get_instance_base_type() : p_arg_type.native_type;
|
||||
}
|
||||
return p_par_type.class_name == class_name || ClassDB::is_parent_class(class_name, p_par_type.class_name);
|
||||
} else {
|
||||
if (p_arg_type.kind != GDScriptDataType::BUILTIN) {
|
||||
return false;
|
||||
}
|
||||
return p_par_type.type == p_arg_type.builtin_type;
|
||||
}
|
||||
}
|
||||
|
||||
static bool _have_exact_arguments(const MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {
|
||||
if (p_method->get_argument_count() != p_arguments.size()) {
|
||||
// ptrcall won't work with default arguments.
|
||||
return false;
|
||||
}
|
||||
MethodInfo info;
|
||||
ClassDB::get_method_info(p_method->get_instance_class(), p_method->get_name(), &info);
|
||||
for (int i = 0; i < p_arguments.size(); i++) {
|
||||
const PropertyInfo &prop = info.arguments[i];
|
||||
if (!_is_exact_type(prop, p_arguments[i].type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root, bool p_initializer, const GDScriptCodeGenerator::Address &p_index_addr) {
|
||||
if (p_expression->is_constant) {
|
||||
return codegen.add_constant(p_expression->reduced_value);
|
||||
|
@ -430,7 +472,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
|||
} else {
|
||||
if (callee->type == GDScriptParser::Node::IDENTIFIER) {
|
||||
// Self function call.
|
||||
if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
|
||||
if (ClassDB::has_method(codegen.script->native->get_name(), call->function_name)) {
|
||||
// Native method, use faster path.
|
||||
GDScriptCodeGenerator::Address self;
|
||||
self.mode = GDScriptCodeGenerator::Address::SELF;
|
||||
MethodBind *method = ClassDB::get_method(codegen.script->native->get_name(), call->function_name);
|
||||
|
||||
if (_have_exact_arguments(method, arguments)) {
|
||||
// Exact arguments, use ptrcall.
|
||||
gen->write_call_ptrcall(result, self, method, arguments);
|
||||
} else {
|
||||
// Not exact arguments, but still can use method bind call.
|
||||
gen->write_call_method_bind(result, self, method, arguments);
|
||||
}
|
||||
} else if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
|
||||
GDScriptCodeGenerator::Address self;
|
||||
self.mode = GDScriptCodeGenerator::Address::CLASS;
|
||||
gen->write_call(result, self, call->function_name, arguments);
|
||||
|
@ -447,6 +502,26 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
|||
}
|
||||
if (within_await) {
|
||||
gen->write_call_async(result, base, call->function_name, arguments);
|
||||
} else if (base.type.has_type && base.type.kind != GDScriptDataType::BUILTIN) {
|
||||
// Native method, use faster path.
|
||||
StringName class_name;
|
||||
if (base.type.kind == GDScriptDataType::NATIVE) {
|
||||
class_name = base.type.native_type;
|
||||
} else {
|
||||
class_name = base.type.native_type == StringName() ? base.type.script_type->get_instance_base_type() : base.type.native_type;
|
||||
}
|
||||
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 (_have_exact_arguments(method, arguments)) {
|
||||
// Exact arguments, use ptrcall.
|
||||
gen->write_call_ptrcall(result, base, method, arguments);
|
||||
} else {
|
||||
// Not exact arguments, but still can use method bind call.
|
||||
gen->write_call_method_bind(result, base, method, arguments);
|
||||
}
|
||||
} else {
|
||||
gen->write_call(result, base, call->function_name, arguments);
|
||||
}
|
||||
} else {
|
||||
gen->write_call(result, base, call->function_name, arguments);
|
||||
}
|
||||
|
@ -493,7 +568,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
|||
GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(get_node->get_datatype()));
|
||||
|
||||
MethodBind *get_node_method = ClassDB::get_method("Node", "get_node");
|
||||
gen->write_call_method_bind(result, GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), get_node_method, args);
|
||||
gen->write_call_ptrcall(result, GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), get_node_method, args);
|
||||
|
||||
return result;
|
||||
} break;
|
||||
|
|
|
@ -466,6 +466,112 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
|
|||
|
||||
incr = 5 + argc;
|
||||
} break;
|
||||
case OPCODE_CALL_METHOD_BIND:
|
||||
case OPCODE_CALL_METHOD_BIND_RET: {
|
||||
bool ret = (_code_ptr[ip] & INSTR_MASK) == OPCODE_CALL_METHOD_BIND_RET;
|
||||
|
||||
if (ret) {
|
||||
text += "call-method_bind-ret ";
|
||||
} else {
|
||||
text += "call-method_bind ";
|
||||
}
|
||||
|
||||
MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
|
||||
|
||||
int argc = _code_ptr[ip + 1 + instr_var_args];
|
||||
if (ret) {
|
||||
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;
|
||||
case OPCODE_CALL_PTRCALL_NO_RETURN: {
|
||||
text += "call-ptrcall (no return) ";
|
||||
|
||||
MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
|
||||
|
||||
int argc = _code_ptr[ip + 1 + instr_var_args];
|
||||
|
||||
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;
|
||||
|
||||
#define DISASSEMBLE_PTRCALL(m_type) \
|
||||
case OPCODE_CALL_PTRCALL_##m_type: { \
|
||||
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(PLANE);
|
||||
DISASSEMBLE_PTRCALL(AABB);
|
||||
DISASSEMBLE_PTRCALL(BASIS);
|
||||
DISASSEMBLE_PTRCALL(TRANSFORM);
|
||||
DISASSEMBLE_PTRCALL(COLOR);
|
||||
DISASSEMBLE_PTRCALL(STRING_NAME);
|
||||
DISASSEMBLE_PTRCALL(NODE_PATH);
|
||||
DISASSEMBLE_PTRCALL(RID);
|
||||
DISASSEMBLE_PTRCALL(QUAT);
|
||||
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_BUILT_IN: {
|
||||
text += "call-built-in ";
|
||||
|
||||
|
|
|
@ -191,6 +191,44 @@ public:
|
|||
OPCODE_CALL_ASYNC,
|
||||
OPCODE_CALL_BUILT_IN,
|
||||
OPCODE_CALL_SELF_BASE,
|
||||
OPCODE_CALL_METHOD_BIND,
|
||||
OPCODE_CALL_METHOD_BIND_RET,
|
||||
// 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_PLANE,
|
||||
OPCODE_CALL_PTRCALL_QUAT,
|
||||
OPCODE_CALL_PTRCALL_AABB,
|
||||
OPCODE_CALL_PTRCALL_BASIS,
|
||||
OPCODE_CALL_PTRCALL_TRANSFORM,
|
||||
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_AWAIT,
|
||||
OPCODE_AWAIT_RESUME,
|
||||
OPCODE_JUMP,
|
||||
|
@ -262,11 +300,15 @@ private:
|
|||
const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr;
|
||||
int _indexed_getters_count = 0;
|
||||
const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr;
|
||||
int _methods_count = 0;
|
||||
MethodBind **_methods_ptr = nullptr;
|
||||
const int *_code_ptr = nullptr;
|
||||
int _code_size = 0;
|
||||
int _argument_count = 0;
|
||||
int _stack_size = 0;
|
||||
int _instruction_args_size = 0;
|
||||
int _ptrcall_args_size = 0;
|
||||
|
||||
int _initial_line = 0;
|
||||
bool _static = false;
|
||||
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
|
||||
|
@ -284,6 +326,7 @@ private:
|
|||
Vector<Variant::ValidatedKeyedGetter> keyed_getters;
|
||||
Vector<Variant::ValidatedIndexedSetter> indexed_setters;
|
||||
Vector<Variant::ValidatedIndexedGetter> indexed_getters;
|
||||
Vector<MethodBind *> methods;
|
||||
Vector<int> code;
|
||||
Vector<GDScriptDataType> argument_types;
|
||||
GDScriptDataType return_type;
|
||||
|
|
|
@ -185,55 +185,92 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
|
|||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define OPCODES_TABLE \
|
||||
static const void *switch_table_ops[] = { \
|
||||
&&OPCODE_OPERATOR, \
|
||||
&&OPCODE_OPERATOR_VALIDATED, \
|
||||
&&OPCODE_EXTENDS_TEST, \
|
||||
&&OPCODE_IS_BUILTIN, \
|
||||
&&OPCODE_SET_KEYED, \
|
||||
&&OPCODE_SET_KEYED_VALIDATED, \
|
||||
&&OPCODE_SET_INDEXED_VALIDATED, \
|
||||
&&OPCODE_GET_KEYED, \
|
||||
&&OPCODE_GET_KEYED_VALIDATED, \
|
||||
&&OPCODE_GET_INDEXED_VALIDATED, \
|
||||
&&OPCODE_SET_NAMED, \
|
||||
&&OPCODE_SET_NAMED_VALIDATED, \
|
||||
&&OPCODE_GET_NAMED, \
|
||||
&&OPCODE_GET_NAMED_VALIDATED, \
|
||||
&&OPCODE_SET_MEMBER, \
|
||||
&&OPCODE_GET_MEMBER, \
|
||||
&&OPCODE_ASSIGN, \
|
||||
&&OPCODE_ASSIGN_TRUE, \
|
||||
&&OPCODE_ASSIGN_FALSE, \
|
||||
&&OPCODE_ASSIGN_TYPED_BUILTIN, \
|
||||
&&OPCODE_ASSIGN_TYPED_NATIVE, \
|
||||
&&OPCODE_ASSIGN_TYPED_SCRIPT, \
|
||||
&&OPCODE_CAST_TO_BUILTIN, \
|
||||
&&OPCODE_CAST_TO_NATIVE, \
|
||||
&&OPCODE_CAST_TO_SCRIPT, \
|
||||
&&OPCODE_CONSTRUCT, \
|
||||
&&OPCODE_CONSTRUCT_ARRAY, \
|
||||
&&OPCODE_CONSTRUCT_DICTIONARY, \
|
||||
&&OPCODE_CALL, \
|
||||
&&OPCODE_CALL_RETURN, \
|
||||
&&OPCODE_CALL_ASYNC, \
|
||||
&&OPCODE_CALL_BUILT_IN, \
|
||||
&&OPCODE_CALL_SELF_BASE, \
|
||||
&&OPCODE_AWAIT, \
|
||||
&&OPCODE_AWAIT_RESUME, \
|
||||
&&OPCODE_JUMP, \
|
||||
&&OPCODE_JUMP_IF, \
|
||||
&&OPCODE_JUMP_IF_NOT, \
|
||||
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
|
||||
&&OPCODE_RETURN, \
|
||||
&&OPCODE_ITERATE_BEGIN, \
|
||||
&&OPCODE_ITERATE, \
|
||||
&&OPCODE_ASSERT, \
|
||||
&&OPCODE_BREAKPOINT, \
|
||||
&&OPCODE_LINE, \
|
||||
&&OPCODE_END \
|
||||
}; \
|
||||
#define OPCODES_TABLE \
|
||||
static const void *switch_table_ops[] = { \
|
||||
&&OPCODE_OPERATOR, \
|
||||
&&OPCODE_OPERATOR_VALIDATED, \
|
||||
&&OPCODE_EXTENDS_TEST, \
|
||||
&&OPCODE_IS_BUILTIN, \
|
||||
&&OPCODE_SET_KEYED, \
|
||||
&&OPCODE_SET_KEYED_VALIDATED, \
|
||||
&&OPCODE_SET_INDEXED_VALIDATED, \
|
||||
&&OPCODE_GET_KEYED, \
|
||||
&&OPCODE_GET_KEYED_VALIDATED, \
|
||||
&&OPCODE_GET_INDEXED_VALIDATED, \
|
||||
&&OPCODE_SET_NAMED, \
|
||||
&&OPCODE_SET_NAMED_VALIDATED, \
|
||||
&&OPCODE_GET_NAMED, \
|
||||
&&OPCODE_GET_NAMED_VALIDATED, \
|
||||
&&OPCODE_SET_MEMBER, \
|
||||
&&OPCODE_GET_MEMBER, \
|
||||
&&OPCODE_ASSIGN, \
|
||||
&&OPCODE_ASSIGN_TRUE, \
|
||||
&&OPCODE_ASSIGN_FALSE, \
|
||||
&&OPCODE_ASSIGN_TYPED_BUILTIN, \
|
||||
&&OPCODE_ASSIGN_TYPED_NATIVE, \
|
||||
&&OPCODE_ASSIGN_TYPED_SCRIPT, \
|
||||
&&OPCODE_CAST_TO_BUILTIN, \
|
||||
&&OPCODE_CAST_TO_NATIVE, \
|
||||
&&OPCODE_CAST_TO_SCRIPT, \
|
||||
&&OPCODE_CONSTRUCT, \
|
||||
&&OPCODE_CONSTRUCT_ARRAY, \
|
||||
&&OPCODE_CONSTRUCT_DICTIONARY, \
|
||||
&&OPCODE_CALL, \
|
||||
&&OPCODE_CALL_RETURN, \
|
||||
&&OPCODE_CALL_ASYNC, \
|
||||
&&OPCODE_CALL_BUILT_IN, \
|
||||
&&OPCODE_CALL_SELF_BASE, \
|
||||
&&OPCODE_CALL_METHOD_BIND, \
|
||||
&&OPCODE_CALL_METHOD_BIND_RET, \
|
||||
&&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_PLANE, \
|
||||
&&OPCODE_CALL_PTRCALL_QUAT, \
|
||||
&&OPCODE_CALL_PTRCALL_AABB, \
|
||||
&&OPCODE_CALL_PTRCALL_BASIS, \
|
||||
&&OPCODE_CALL_PTRCALL_TRANSFORM, \
|
||||
&&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_AWAIT, \
|
||||
&&OPCODE_AWAIT_RESUME, \
|
||||
&&OPCODE_JUMP, \
|
||||
&&OPCODE_JUMP_IF, \
|
||||
&&OPCODE_JUMP_IF_NOT, \
|
||||
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
|
||||
&&OPCODE_RETURN, \
|
||||
&&OPCODE_ITERATE_BEGIN, \
|
||||
&&OPCODE_ITERATE, \
|
||||
&&OPCODE_ASSERT, \
|
||||
&&OPCODE_BREAKPOINT, \
|
||||
&&OPCODE_LINE, \
|
||||
&&OPCODE_END \
|
||||
}; \
|
||||
static_assert((sizeof(switch_table_ops) / sizeof(switch_table_ops[0]) == (OPCODE_END + 1)), "Opcodes in jump table aren't the same as opcodes in enum.");
|
||||
|
||||
#define OPCODE(m_op) \
|
||||
|
@ -260,6 +297,41 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
|
|||
#define OPCODE_OUT break
|
||||
#endif
|
||||
|
||||
// Helpers for VariantInternal methods in macros.
|
||||
#define OP_GET_BOOL get_bool
|
||||
#define OP_GET_INT get_int
|
||||
#define OP_GET_FLOAT get_float
|
||||
#define OP_GET_VECTOR2 get_vector2
|
||||
#define OP_GET_VECTOR2I get_vector2i
|
||||
#define OP_GET_VECTOR3 get_vector3
|
||||
#define OP_GET_VECTOR3I get_vector3i
|
||||
#define OP_GET_RECT2 get_rect2
|
||||
#define OP_GET_RECT2I get_rect2i
|
||||
#define OP_GET_QUAT get_quat
|
||||
#define OP_GET_COLOR get_color
|
||||
#define OP_GET_STRING get_string
|
||||
#define OP_GET_STRING_NAME get_string_name
|
||||
#define OP_GET_NODE_PATH get_node_path
|
||||
#define OP_GET_CALLABLE get_callable
|
||||
#define OP_GET_SIGNAL get_signal
|
||||
#define OP_GET_ARRAY get_array
|
||||
#define OP_GET_DICTIONARY get_dictionary
|
||||
#define OP_GET_PACKED_BYTE_ARRAY get_byte_array
|
||||
#define OP_GET_PACKED_INT32_ARRAY get_int32_array
|
||||
#define OP_GET_PACKED_INT64_ARRAY get_int64_array
|
||||
#define OP_GET_PACKED_FLOAT32_ARRAY get_float32_array
|
||||
#define OP_GET_PACKED_FLOAT64_ARRAY get_float64_array
|
||||
#define OP_GET_PACKED_STRING_ARRAY get_string_array
|
||||
#define OP_GET_PACKED_VECTOR2_ARRAY get_vector2_array
|
||||
#define OP_GET_PACKED_VECTOR3_ARRAY get_vector3_array
|
||||
#define OP_GET_PACKED_COLOR_ARRAY get_color_array
|
||||
#define OP_GET_TRANSFORM get_transform
|
||||
#define OP_GET_TRANSFORM2D get_transform2d
|
||||
#define OP_GET_PLANE get_plane
|
||||
#define OP_GET_AABB get_aabb
|
||||
#define OP_GET_BASIS get_basis
|
||||
#define OP_GET_RID get_rid
|
||||
|
||||
Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state) {
|
||||
OPCODES_TABLE;
|
||||
|
||||
|
@ -274,6 +346,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
Variant retvalue;
|
||||
Variant *stack = nullptr;
|
||||
Variant **instruction_args;
|
||||
const void **call_args_ptr = nullptr;
|
||||
int defarg = 0;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
@ -371,6 +444,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
script = _script;
|
||||
}
|
||||
}
|
||||
if (_ptrcall_args_size) {
|
||||
call_args_ptr = (const void **)alloca(_ptrcall_args_size * sizeof(void *));
|
||||
} else {
|
||||
call_args_ptr = nullptr;
|
||||
}
|
||||
|
||||
static_ref = script;
|
||||
|
||||
|
@ -1296,6 +1374,285 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
}
|
||||
DISPATCH_OPCODE;
|
||||
|
||||
OPCODE(OPCODE_CALL_METHOD_BIND)
|
||||
OPCODE(OPCODE_CALL_METHOD_BIND_RET) {
|
||||
CHECK_SPACE(3 + instr_arg_count);
|
||||
bool call_ret = (_code_ptr[ip] & INSTR_MASK) == OPCODE_CALL_METHOD_BIND_RET;
|
||||
|
||||
ip += instr_arg_count;
|
||||
|
||||
int argc = _code_ptr[ip + 1];
|
||||
GD_ERR_BREAK(argc < 0);
|
||||
GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count);
|
||||
MethodBind *method = _methods_ptr[_code_ptr[ip + 2]];
|
||||
|
||||
GET_INSTRUCTION_ARG(base, argc);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
bool freed = false;
|
||||
Object *base_obj = base->get_validated_object_with_check(freed);
|
||||
if (freed) {
|
||||
err_text = "Trying to call a function on a previously freed instance.";
|
||||
OPCODE_BREAK;
|
||||
} else if (!base_obj) {
|
||||
err_text = "Trying to call a function on a null value.";
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
#else
|
||||
Object *base_obj = base->operator Object *();
|
||||
#endif
|
||||
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
|
||||
|
||||
Callable::CallError err;
|
||||
if (call_ret) {
|
||||
GET_INSTRUCTION_ARG(ret, argc + 1);
|
||||
*ret = method->call(base_obj, (const Variant **)argptrs, argc, err);
|
||||
} else {
|
||||
method->call(base_obj, (const Variant **)argptrs, argc, err);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (GDScriptLanguage::get_singleton()->profiling) {
|
||||
function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
|
||||
}
|
||||
|
||||
if (err.error != Callable::CallError::CALL_OK) {
|
||||
String methodstr = method->get_name();
|
||||
String basestr = _get_var_type(base);
|
||||
|
||||
if (methodstr == "call") {
|
||||
if (argc >= 1) {
|
||||
methodstr = String(*argptrs[0]) + " (via call)";
|
||||
if (err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
|
||||
err.argument += 1;
|
||||
}
|
||||
}
|
||||
} else if (methodstr == "free") {
|
||||
if (err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
|
||||
if (base->is_ref()) {
|
||||
err_text = "Attempted to free a reference.";
|
||||
OPCODE_BREAK;
|
||||
} else if (base->get_type() == Variant::OBJECT) {
|
||||
err_text = "Attempted to free a locked object (calling or emitting).";
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
}
|
||||
}
|
||||
err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
#endif
|
||||
ip += 3;
|
||||
}
|
||||
DISPATCH_OPCODE;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
#define OPCODE_CALL_PTR(m_type) \
|
||||
OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
|
||||
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] >= _methods_count); \
|
||||
MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; \
|
||||
bool freed = false; \
|
||||
Object *base_obj = base->get_validated_object_with_check(freed); \
|
||||
if (freed) { \
|
||||
err_text = "Trying to call a function on a previously freed instance."; \
|
||||
OPCODE_BREAK; \
|
||||
} else if (!base_obj) { \
|
||||
err_text = "Trying to call a function on a null value."; \
|
||||
OPCODE_BREAK; \
|
||||
} \
|
||||
const void **argptrs = call_args_ptr; \
|
||||
for (int i = 0; i < argc; i++) { \
|
||||
GET_INSTRUCTION_ARG(v, i); \
|
||||
argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v); \
|
||||
} \
|
||||
uint64_t call_time = 0; \
|
||||
if (GDScriptLanguage::get_singleton()->profiling) { \
|
||||
call_time = OS::get_singleton()->get_ticks_usec(); \
|
||||
} \
|
||||
GET_INSTRUCTION_ARG(ret, argc + 1); \
|
||||
VariantInternal::initialize(ret, Variant::m_type); \
|
||||
void *ret_opaque = VariantInternal::OP_GET_##m_type(ret); \
|
||||
method->ptrcall(base_obj, argptrs, ret_opaque); \
|
||||
if (GDScriptLanguage::get_singleton()->profiling) { \
|
||||
function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; \
|
||||
} \
|
||||
ip += 3; \
|
||||
} \
|
||||
DISPATCH_OPCODE
|
||||
#else
|
||||
#define OPCODE_CALL_PTR(m_type) \
|
||||
OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
|
||||
CHECK_SPACE(3 + instr_arg_count); \
|
||||
int argc = _code_ptr[ip + 1]; \
|
||||
GET_INSTRUCTION_ARG(base, argc); \
|
||||
MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; \
|
||||
Object *base_obj = *VariantInternal::get_object(base); \
|
||||
const void **argptrs = call_args_ptr; \
|
||||
for (int i = 0; i < argc; i++) { \
|
||||
GET_INSTRUCTION_ARG(v, i); \
|
||||
argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v); \
|
||||
} \
|
||||
GET_INSTRUCTION_ARG(ret, argc + 1); \
|
||||
VariantInternal::initialize(ret, Variant::m_type); \
|
||||
void *ret_opaque = VariantInternal::OP_GET_##m_type(ret); \
|
||||
method->ptrcall(base_obj, argptrs, ret_opaque); \
|
||||
ip += 3; \
|
||||
} \
|
||||
DISPATCH_OPCODE
|
||||
#endif
|
||||
|
||||
OPCODE_CALL_PTR(BOOL);
|
||||
OPCODE_CALL_PTR(INT);
|
||||
OPCODE_CALL_PTR(FLOAT);
|
||||
OPCODE_CALL_PTR(STRING);
|
||||
OPCODE_CALL_PTR(VECTOR2);
|
||||
OPCODE_CALL_PTR(VECTOR2I);
|
||||
OPCODE_CALL_PTR(RECT2);
|
||||
OPCODE_CALL_PTR(RECT2I);
|
||||
OPCODE_CALL_PTR(VECTOR3);
|
||||
OPCODE_CALL_PTR(VECTOR3I);
|
||||
OPCODE_CALL_PTR(TRANSFORM2D);
|
||||
OPCODE_CALL_PTR(PLANE);
|
||||
OPCODE_CALL_PTR(QUAT);
|
||||
OPCODE_CALL_PTR(AABB);
|
||||
OPCODE_CALL_PTR(BASIS);
|
||||
OPCODE_CALL_PTR(TRANSFORM);
|
||||
OPCODE_CALL_PTR(COLOR);
|
||||
OPCODE_CALL_PTR(STRING_NAME);
|
||||
OPCODE_CALL_PTR(NODE_PATH);
|
||||
OPCODE_CALL_PTR(RID);
|
||||
OPCODE_CALL_PTR(CALLABLE);
|
||||
OPCODE_CALL_PTR(SIGNAL);
|
||||
OPCODE_CALL_PTR(DICTIONARY);
|
||||
OPCODE_CALL_PTR(ARRAY);
|
||||
OPCODE_CALL_PTR(PACKED_BYTE_ARRAY);
|
||||
OPCODE_CALL_PTR(PACKED_INT32_ARRAY);
|
||||
OPCODE_CALL_PTR(PACKED_INT64_ARRAY);
|
||||
OPCODE_CALL_PTR(PACKED_FLOAT32_ARRAY);
|
||||
OPCODE_CALL_PTR(PACKED_FLOAT64_ARRAY);
|
||||
OPCODE_CALL_PTR(PACKED_STRING_ARRAY);
|
||||
OPCODE_CALL_PTR(PACKED_VECTOR2_ARRAY);
|
||||
OPCODE_CALL_PTR(PACKED_VECTOR3_ARRAY);
|
||||
OPCODE_CALL_PTR(PACKED_COLOR_ARRAY);
|
||||
OPCODE(OPCODE_CALL_PTRCALL_OBJECT) {
|
||||
CHECK_SPACE(3 + instr_arg_count);
|
||||
|
||||
ip += instr_arg_count;
|
||||
|
||||
int argc = _code_ptr[ip + 1];
|
||||
GD_ERR_BREAK(argc < 0);
|
||||
|
||||
GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count);
|
||||
MethodBind *method = _methods_ptr[_code_ptr[ip + 2]];
|
||||
|
||||
GET_INSTRUCTION_ARG(base, argc);
|
||||
#ifdef DEBUG_ENABLED
|
||||
bool freed = false;
|
||||
Object *base_obj = base->get_validated_object_with_check(freed);
|
||||
if (freed) {
|
||||
err_text = "Trying to call a function on a previously freed instance.";
|
||||
OPCODE_BREAK;
|
||||
} else if (!base_obj) {
|
||||
err_text = "Trying to call a function on a null value.";
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
#else
|
||||
Object *base_obj = *VariantInternal::get_object(base);
|
||||
#endif
|
||||
|
||||
const void **argptrs = call_args_ptr;
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
GET_INSTRUCTION_ARG(v, i);
|
||||
argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v);
|
||||
}
|
||||
#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);
|
||||
VariantInternal::initialize(ret, Variant::OBJECT);
|
||||
Object **ret_opaque = VariantInternal::get_object(ret);
|
||||
method->ptrcall(base_obj, argptrs, ret_opaque);
|
||||
VariantInternal::set_object(ret, *ret_opaque);
|
||||
|
||||
#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_PTRCALL_NO_RETURN) {
|
||||
CHECK_SPACE(3 + instr_arg_count);
|
||||
|
||||
ip += instr_arg_count;
|
||||
|
||||
int argc = _code_ptr[ip + 1];
|
||||
GD_ERR_BREAK(argc < 0);
|
||||
|
||||
GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count);
|
||||
MethodBind *method = _methods_ptr[_code_ptr[ip + 2]];
|
||||
|
||||
GET_INSTRUCTION_ARG(base, argc);
|
||||
#ifdef DEBUG_ENABLED
|
||||
bool freed = false;
|
||||
Object *base_obj = base->get_validated_object_with_check(freed);
|
||||
if (freed) {
|
||||
err_text = "Trying to call a function on a previously freed instance.";
|
||||
OPCODE_BREAK;
|
||||
} else if (!base_obj) {
|
||||
err_text = "Trying to call a function on a null value.";
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
#else
|
||||
Object *base_obj = *VariantInternal::get_object(base);
|
||||
#endif
|
||||
const void **argptrs = call_args_ptr;
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
GET_INSTRUCTION_ARG(v, i);
|
||||
argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v);
|
||||
}
|
||||
#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);
|
||||
VariantInternal::initialize(ret, Variant::NIL);
|
||||
method->ptrcall(base_obj, argptrs, nullptr);
|
||||
|
||||
#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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue