mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
Reduce number of addressing modes in GDScript VM
There's now only 3 addressing modes: stack, constant, and member. Self, class, and nil are now present respectively in the first 3 stack slots. Global and class constants are moved to local constants when compiling. Named globals is only present on editor to use on tool singletons, so its use now emits a new instruction to copy the global to the stack. This allow us to further optimize the VM later by embedding the addressing modes in the instructions themselves, which is better done with less permutations.
This commit is contained in:
parent
084b882c0a
commit
cf4079cb5f
8 changed files with 129 additions and 194 deletions
|
@ -34,22 +34,22 @@
|
|||
#include "core/os/os.h"
|
||||
#include "gdscript.h"
|
||||
|
||||
Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const {
|
||||
Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const {
|
||||
int address = p_address & ADDR_MASK;
|
||||
|
||||
//sequential table (jump table generated by compiler)
|
||||
switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) {
|
||||
case ADDR_TYPE_SELF: {
|
||||
case ADDR_TYPE_STACK: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (unlikely(!p_instance)) {
|
||||
r_error = "Cannot access self without instance.";
|
||||
return nullptr;
|
||||
}
|
||||
ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
|
||||
#endif
|
||||
return &self;
|
||||
return &p_stack[address];
|
||||
} break;
|
||||
case ADDR_TYPE_CLASS: {
|
||||
return &static_ref;
|
||||
case ADDR_TYPE_CONSTANT: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
|
||||
#endif
|
||||
return &_constants_ptr[address];
|
||||
} break;
|
||||
case ADDR_TYPE_MEMBER: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
@ -61,65 +61,6 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
|
|||
//member indexing is O(1)
|
||||
return &p_instance->members.write[address];
|
||||
} break;
|
||||
case ADDR_TYPE_CLASS_CONSTANT: {
|
||||
//todo change to index!
|
||||
GDScript *s = p_script;
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
|
||||
#endif
|
||||
const StringName *sn = &_global_names_ptr[address];
|
||||
|
||||
while (s) {
|
||||
GDScript *o = s;
|
||||
while (o) {
|
||||
Map<StringName, Variant>::Element *E = o->constants.find(*sn);
|
||||
if (E) {
|
||||
return &E->get();
|
||||
}
|
||||
o = o->_owner;
|
||||
}
|
||||
s = s->_base;
|
||||
}
|
||||
|
||||
ERR_FAIL_V_MSG(nullptr, "GDScriptCompiler bug.");
|
||||
} break;
|
||||
case ADDR_TYPE_LOCAL_CONSTANT: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
|
||||
#endif
|
||||
return &_constants_ptr[address];
|
||||
} break;
|
||||
case ADDR_TYPE_STACK:
|
||||
case ADDR_TYPE_STACK_VARIABLE: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
|
||||
#endif
|
||||
return &p_stack[address];
|
||||
} break;
|
||||
case ADDR_TYPE_GLOBAL: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_INDEX_V(address, GDScriptLanguage::get_singleton()->get_global_array_size(), nullptr);
|
||||
#endif
|
||||
return &GDScriptLanguage::get_singleton()->get_global_array()[address];
|
||||
} break;
|
||||
#ifdef TOOLS_ENABLED
|
||||
case ADDR_TYPE_NAMED_GLOBAL: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
|
||||
#endif
|
||||
StringName id = _global_names_ptr[address];
|
||||
|
||||
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(id)) {
|
||||
return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id];
|
||||
} else {
|
||||
r_error = "Autoload singleton '" + String(id) + "' has been removed.";
|
||||
return nullptr;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
case ADDR_TYPE_NIL: {
|
||||
return &nil;
|
||||
} break;
|
||||
}
|
||||
|
||||
ERR_FAIL_V_MSG(nullptr, "Bad code! (unknown addressing mode).");
|
||||
|
@ -340,6 +281,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
|
|||
&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
|
||||
&&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
|
||||
&&OPCODE_ITERATE_OBJECT, \
|
||||
&&OPCODE_STORE_NAMED_GLOBAL, \
|
||||
&&OPCODE_ASSERT, \
|
||||
&&OPCODE_BREAKPOINT, \
|
||||
&&OPCODE_LINE, \
|
||||
|
@ -415,11 +357,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
|
||||
r_err.error = Callable::CallError::CALL_OK;
|
||||
|
||||
Variant self;
|
||||
Variant static_ref;
|
||||
Variant retvalue;
|
||||
Variant *stack = nullptr;
|
||||
Variant **instruction_args;
|
||||
Variant **instruction_args = nullptr;
|
||||
const void **call_args_ptr = nullptr;
|
||||
int defarg = 0;
|
||||
|
||||
|
@ -444,7 +384,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
script = p_state->script;
|
||||
p_instance = p_state->instance;
|
||||
defarg = p_state->defarg;
|
||||
self = p_state->self;
|
||||
|
||||
} else {
|
||||
if (p_argcount != _argument_count) {
|
||||
|
@ -462,55 +401,49 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
}
|
||||
}
|
||||
|
||||
alloca_size = sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size;
|
||||
// Add 3 here for self, class, and nil.
|
||||
alloca_size = sizeof(Variant *) * 3 + sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size;
|
||||
|
||||
if (alloca_size) {
|
||||
uint8_t *aptr = (uint8_t *)alloca(alloca_size);
|
||||
uint8_t *aptr = (uint8_t *)alloca(alloca_size);
|
||||
stack = (Variant *)aptr;
|
||||
|
||||
if (_stack_size) {
|
||||
stack = (Variant *)aptr;
|
||||
for (int i = 0; i < p_argcount; i++) {
|
||||
if (!argument_types[i].has_type) {
|
||||
memnew_placement(&stack[i], Variant(*p_args[i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!argument_types[i].is_type(*p_args[i], true)) {
|
||||
r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_err.argument = i;
|
||||
r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
|
||||
return Variant();
|
||||
}
|
||||
if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
|
||||
Variant arg;
|
||||
Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err);
|
||||
memnew_placement(&stack[i], Variant(arg));
|
||||
} else {
|
||||
memnew_placement(&stack[i], Variant(*p_args[i]));
|
||||
}
|
||||
}
|
||||
for (int i = p_argcount; i < _stack_size; i++) {
|
||||
memnew_placement(&stack[i], Variant);
|
||||
}
|
||||
} else {
|
||||
stack = nullptr;
|
||||
for (int i = 0; i < p_argcount; i++) {
|
||||
if (!argument_types[i].has_type) {
|
||||
memnew_placement(&stack[i + 3], Variant(*p_args[i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_instruction_args_size) {
|
||||
instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
|
||||
} else {
|
||||
instruction_args = nullptr;
|
||||
if (!argument_types[i].is_type(*p_args[i], true)) {
|
||||
r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_err.argument = i;
|
||||
r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
|
||||
return Variant();
|
||||
}
|
||||
if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
|
||||
Variant arg;
|
||||
Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err);
|
||||
memnew_placement(&stack[i + 3], Variant(arg));
|
||||
} else {
|
||||
memnew_placement(&stack[i + 3], Variant(*p_args[i]));
|
||||
}
|
||||
}
|
||||
for (int i = p_argcount + 3; i < _stack_size; i++) {
|
||||
memnew_placement(&stack[i], Variant);
|
||||
}
|
||||
|
||||
memnew_placement(&stack[ADDR_STACK_NIL], Variant);
|
||||
|
||||
if (_instruction_args_size) {
|
||||
instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
|
||||
} else {
|
||||
stack = nullptr;
|
||||
instruction_args = nullptr;
|
||||
}
|
||||
|
||||
if (p_instance) {
|
||||
self = p_instance->owner;
|
||||
memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
|
||||
script = p_instance->script.ptr();
|
||||
} else {
|
||||
memnew_placement(&stack[ADDR_STACK_SELF], Variant);
|
||||
script = _script;
|
||||
}
|
||||
}
|
||||
|
@ -520,7 +453,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
call_args_ptr = nullptr;
|
||||
}
|
||||
|
||||
static_ref = script;
|
||||
memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
|
||||
|
||||
String err_text;
|
||||
|
||||
|
@ -541,10 +474,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
#define CHECK_SPACE(m_space) \
|
||||
GD_ERR_BREAK((ip + m_space) > _code_size)
|
||||
|
||||
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
|
||||
Variant *m_v; \
|
||||
m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text); \
|
||||
if (unlikely(!m_v)) \
|
||||
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
|
||||
Variant *m_v; \
|
||||
m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, stack, err_text); \
|
||||
if (unlikely(!m_v)) \
|
||||
OPCODE_BREAK;
|
||||
|
||||
#else
|
||||
|
@ -552,7 +485,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
#define CHECK_SPACE(m_space)
|
||||
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
|
||||
Variant *m_v; \
|
||||
m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text);
|
||||
m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, stack, err_text);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -2038,7 +1971,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i]));
|
||||
}
|
||||
gdfs->state.stack_size = _stack_size;
|
||||
gdfs->state.self = self;
|
||||
gdfs->state.alloca_size = alloca_size;
|
||||
gdfs->state.ip = ip + 2;
|
||||
gdfs->state.line = line;
|
||||
|
@ -3028,6 +2960,19 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
}
|
||||
DISPATCH_OPCODE;
|
||||
|
||||
OPCODE(OPCODE_STORE_NAMED_GLOBAL) {
|
||||
CHECK_SPACE(3);
|
||||
int globalname_idx = _code_ptr[ip + 2];
|
||||
GD_ERR_BREAK(globalname_idx < 0 || globalname_idx >= _global_names_count);
|
||||
const StringName *globalname = &_global_names_ptr[globalname_idx];
|
||||
|
||||
GET_INSTRUCTION_ARG(dst, 0);
|
||||
*dst = GDScriptLanguage::get_singleton()->get_named_globals_map()[*globalname];
|
||||
|
||||
ip += 3;
|
||||
}
|
||||
DISPATCH_OPCODE;
|
||||
|
||||
OPCODE(OPCODE_ASSERT) {
|
||||
CHECK_SPACE(3);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue