1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +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:
George Marques
2021-04-08 11:55:24 -03:00
parent 084b882c0a
commit cf4079cb5f
8 changed files with 129 additions and 194 deletions

View File

@@ -59,12 +59,7 @@ uint32_t GDScriptByteCodeGenerator::add_local_constant(const StringName &p_name,
} }
uint32_t GDScriptByteCodeGenerator::add_or_get_constant(const Variant &p_constant) { uint32_t GDScriptByteCodeGenerator::add_or_get_constant(const Variant &p_constant) {
if (constant_map.has(p_constant)) { return get_constant_pos(p_constant);
return constant_map[p_constant];
}
int index = constant_map.size();
constant_map[p_constant] = index;
return index;
} }
uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) { uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) {
@@ -612,7 +607,8 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
} break; } break;
case GDScriptDataType::NATIVE: { case GDScriptDataType::NATIVE: {
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type]; int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type];
class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE, 3); append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE, 3);
append(p_target); append(p_target);
append(p_source); append(p_source);
@@ -621,8 +617,7 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
case GDScriptDataType::SCRIPT: case GDScriptDataType::SCRIPT:
case GDScriptDataType::GDSCRIPT: { case GDScriptDataType::GDSCRIPT: {
Variant script = p_target.type.script_type; Variant script = p_target.type.script_type;
int idx = get_constant_pos(script); int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT, 3); append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT, 3);
append(p_target); append(p_target);
@@ -673,6 +668,12 @@ void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_
function->default_arguments.push_back(opcodes.size()); function->default_arguments.push_back(opcodes.size());
} }
void GDScriptByteCodeGenerator::write_store_named_global(const Address &p_dst, const StringName &p_global) {
append(GDScriptFunction::OPCODE_STORE_NAMED_GLOBAL, 1);
append(p_dst);
append(p_global);
}
void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) { void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {
int index = 0; int index = 0;
@@ -683,16 +684,14 @@ void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Addres
} break; } break;
case GDScriptDataType::NATIVE: { case GDScriptDataType::NATIVE: {
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_type.native_type]; int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_type.native_type];
class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
append(GDScriptFunction::OPCODE_CAST_TO_NATIVE, 3); append(GDScriptFunction::OPCODE_CAST_TO_NATIVE, 3);
index = class_idx; index = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
} break; } break;
case GDScriptDataType::SCRIPT: case GDScriptDataType::SCRIPT:
case GDScriptDataType::GDSCRIPT: { case GDScriptDataType::GDSCRIPT: {
Variant script = p_type.script_type; Variant script = p_type.script_type;
int idx = get_constant_pos(script); int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_CAST_TO_SCRIPT, 3); append(GDScriptFunction::OPCODE_CAST_TO_SCRIPT, 3);
index = idx; index = idx;
} break; } break;
@@ -903,7 +902,7 @@ void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const S
for (int i = 0; i < p_arguments.size(); i++) { for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]); append(p_arguments[i]);
} }
append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); append(GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
append(p_target); append(p_target);
append(p_arguments.size()); append(p_arguments.size());
append(p_function_name); append(p_function_name);
@@ -914,7 +913,7 @@ void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, c
for (int i = 0; i < p_arguments.size(); i++) { for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]); append(p_arguments[i]);
} }
append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); append(GDScriptFunction::ADDR_SELF);
append(p_target); append(p_target);
append(p_arguments.size()); append(p_arguments.size());
append(p_function_name); append(p_function_name);
@@ -999,7 +998,7 @@ void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_tar
if (p_element_type.script_type) { if (p_element_type.script_type) {
Variant script_type = Ref<Script>(p_element_type.script_type); Variant script_type = Ref<Script>(p_element_type.script_type);
int addr = get_constant_pos(script_type); int addr = get_constant_pos(script_type);
addr |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; addr |= GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS;
append(addr); append(addr);
} else { } else {
append(Address()); // null. append(Address()); // null.
@@ -1296,8 +1295,7 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
const GDScriptDataType &element_type = function->return_type.get_container_element_type(); const GDScriptDataType &element_type = function->return_type.get_container_element_type();
Variant script = function->return_type.script_type; Variant script = function->return_type.script_type;
int script_idx = get_constant_pos(script); int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2); append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
append(p_return_value); append(p_return_value);
@@ -1326,7 +1324,7 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
Variant script = function->return_type.script_type; Variant script = function->return_type.script_type;
int script_idx = get_constant_pos(script); int script_idx = get_constant_pos(script);
script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); script_idx |= (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2); append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
append(p_return_value); append(p_return_value);
@@ -1343,14 +1341,14 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
append(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE, 2); append(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE, 2);
append(p_return_value); append(p_return_value);
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type]; int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];
class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
append(class_idx); append(class_idx);
} break; } break;
case GDScriptDataType::GDSCRIPT: case GDScriptDataType::GDSCRIPT:
case GDScriptDataType::SCRIPT: { case GDScriptDataType::SCRIPT: {
Variant script = function->return_type.script_type; Variant script = function->return_type.script_type;
int script_idx = get_constant_pos(script); int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT, 2); append(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT, 2);
append(p_return_value); append(p_return_value);

View File

@@ -51,11 +51,11 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
List<Map<StringName, int>> block_identifier_stack; List<Map<StringName, int>> block_identifier_stack;
Map<StringName, int> block_identifiers; Map<StringName, int> block_identifiers;
int current_stack_size = 0; int current_stack_size = 3; // First 3 spots are reserved for self, class, and nil.
int current_temporaries = 0; int current_temporaries = 0;
int current_locals = 0; int current_locals = 0;
int current_line = 0; int current_line = 0;
int stack_max = 0; int stack_max = 3;
int instr_args_max = 0; int instr_args_max = 0;
int ptrcall_max = 0; int ptrcall_max = 0;
@@ -135,7 +135,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(current_temporaries)); ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(current_temporaries));
} }
#endif #endif
current_stack_size = current_locals; current_stack_size = current_locals + 3; // Keep the 3 reserved slots for self, class, and nil.
if (debug_stack) { if (debug_stack) {
for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) { for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) {
@@ -300,26 +300,19 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
int address_of(const Address &p_address) { int address_of(const Address &p_address) {
switch (p_address.mode) { switch (p_address.mode) {
case Address::SELF: case Address::SELF:
return GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS; return GDScriptFunction::ADDR_SELF;
case Address::CLASS: case Address::CLASS:
return GDScriptFunction::ADDR_TYPE_CLASS << GDScriptFunction::ADDR_BITS; return GDScriptFunction::ADDR_CLASS;
case Address::MEMBER: case Address::MEMBER:
return p_address.address | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS); return p_address.address | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS);
case Address::CLASS_CONSTANT:
return p_address.address | (GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS);
case Address::LOCAL_CONSTANT:
case Address::CONSTANT: case Address::CONSTANT:
return p_address.address | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); return p_address.address | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
case Address::LOCAL_VARIABLE: case Address::LOCAL_VARIABLE:
case Address::TEMPORARY: case Address::TEMPORARY:
case Address::FUNCTION_PARAMETER: case Address::FUNCTION_PARAMETER:
return p_address.address | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); return p_address.address | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
case Address::GLOBAL:
return p_address.address | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
case Address::NAMED_GLOBAL:
return p_address.address | (GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL << GDScriptFunction::ADDR_BITS);
case Address::NIL: case Address::NIL:
return GDScriptFunction::ADDR_TYPE_NIL << GDScriptFunction::ADDR_BITS; return GDScriptFunction::ADDR_NIL;
} }
return -1; // Unreachable. return -1; // Unreachable.
} }
@@ -441,6 +434,7 @@ public:
virtual void write_assign_true(const Address &p_target) override; virtual void write_assign_true(const Address &p_target) override;
virtual void write_assign_false(const Address &p_target) override; virtual void write_assign_false(const Address &p_target) override;
virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override; virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override;
virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) override;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override; virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override; virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override; virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;

View File

@@ -45,13 +45,9 @@ public:
CLASS, CLASS,
MEMBER, MEMBER,
CONSTANT, CONSTANT,
CLASS_CONSTANT,
LOCAL_CONSTANT,
LOCAL_VARIABLE, LOCAL_VARIABLE,
FUNCTION_PARAMETER, FUNCTION_PARAMETER,
TEMPORARY, TEMPORARY,
GLOBAL,
NAMED_GLOBAL,
NIL, NIL,
}; };
AddressMode mode = NIL; AddressMode mode = NIL;
@@ -123,6 +119,7 @@ public:
virtual void write_assign_true(const Address &p_target) = 0; virtual void write_assign_true(const Address &p_target) = 0;
virtual void write_assign_false(const Address &p_target) = 0; virtual void write_assign_false(const Address &p_target) = 0;
virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0; virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0;
virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) = 0;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0; virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;

View File

@@ -262,7 +262,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
GDScriptNativeClass *nc = nullptr; GDScriptNativeClass *nc = nullptr;
while (scr) { while (scr) {
if (scr->constants.has(identifier)) { if (scr->constants.has(identifier)) {
return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS_CONSTANT, gen->add_or_get_name(identifier)); // TODO: Get type here. return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here.
} }
if (scr->native.is_valid()) { if (scr->native.is_valid()) {
nc = scr->native.ptr(); nc = scr->native.ptr();
@@ -319,7 +319,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier]; int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::GLOBAL, idx); // TODO: Get type. Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
return codegen.add_constant(global); // TODO: Get type.
} }
// Try global classes. // Try global classes.
@@ -347,7 +348,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) { if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NAMED_GLOBAL, gen->add_or_get_name(identifier)); // TODO: Get type. GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type.
gen->write_store_named_global(global, identifier);
return global;
} }
#endif #endif

View File

@@ -61,7 +61,7 @@ class GDScriptCompiler {
GDScriptCodeGenerator::Address add_local_constant(const StringName &p_name, const Variant &p_value) { GDScriptCodeGenerator::Address add_local_constant(const StringName &p_name, const Variant &p_value) {
uint32_t addr = generator->add_local_constant(p_name, p_value); uint32_t addr = generator->add_local_constant(p_name, p_value);
locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_CONSTANT, addr); locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CONSTANT, addr);
return locals[p_name]; return locals[p_name];
} }

View File

@@ -69,35 +69,23 @@ static String _disassemble_address(const GDScript *p_script, const GDScriptFunct
int addr = p_address & GDScriptFunction::ADDR_MASK; int addr = p_address & GDScriptFunction::ADDR_MASK;
switch (p_address >> GDScriptFunction::ADDR_BITS) { switch (p_address >> GDScriptFunction::ADDR_BITS) {
case GDScriptFunction::ADDR_TYPE_SELF: {
return "self";
} break;
case GDScriptFunction::ADDR_TYPE_CLASS: {
return "class";
} break;
case GDScriptFunction::ADDR_TYPE_MEMBER: { case GDScriptFunction::ADDR_TYPE_MEMBER: {
return "member(" + p_script->debug_get_member_by_index(addr) + ")"; return "member(" + p_script->debug_get_member_by_index(addr) + ")";
} break; } break;
case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: { case GDScriptFunction::ADDR_TYPE_CONSTANT: {
return "class_const(" + p_function.get_global_name(addr) + ")";
} break;
case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: {
return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")"; return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")";
} break; } break;
case GDScriptFunction::ADDR_TYPE_STACK: { case GDScriptFunction::ADDR_TYPE_STACK: {
return "stack(" + itos(addr) + ")"; switch (addr) {
} break; case GDScriptFunction::ADDR_STACK_SELF:
case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: { return "self";
return "var_stack(" + itos(addr) + ")"; case GDScriptFunction::ADDR_STACK_CLASS:
} break; return "class";
case GDScriptFunction::ADDR_TYPE_GLOBAL: { case GDScriptFunction::ADDR_STACK_NIL:
return "global(" + _get_variant_string(GDScriptLanguage::get_singleton()->get_global_array()[addr]) + ")"; return "nil";
} break; default:
case GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL: { return "stack(" + itos(addr) + ")";
return "named_global(" + p_function.get_global_name(addr) + ")"; }
} break;
case GDScriptFunction::ADDR_TYPE_NIL: {
return "nil";
} break; } break;
} }
@@ -885,6 +873,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 5; incr += 5;
} break; } break;
DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE); DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE);
case OPCODE_STORE_NAMED_GLOBAL: {
text += "store named global ";
text += DADDR(1);
text += " = ";
text += String(_global_names_ptr[_code_ptr[ip + 2]]);
incr += 3;
} break;
case OPCODE_LINE: { case OPCODE_LINE: {
int line = _code_ptr[ip + 1] - 1; int line = _code_ptr[ip + 1] - 1;
if (line >= 0 && line < p_code_lines.size()) { if (line >= 0 && line < p_code_lines.size()) {

View File

@@ -350,6 +350,7 @@ public:
OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, OPCODE_ITERATE_PACKED_VECTOR3_ARRAY,
OPCODE_ITERATE_PACKED_COLOR_ARRAY, OPCODE_ITERATE_PACKED_COLOR_ARRAY,
OPCODE_ITERATE_OBJECT, OPCODE_ITERATE_OBJECT,
OPCODE_STORE_NAMED_GLOBAL,
OPCODE_ASSERT, OPCODE_ASSERT,
OPCODE_BREAKPOINT, OPCODE_BREAKPOINT,
OPCODE_LINE, OPCODE_LINE,
@@ -360,16 +361,18 @@ public:
ADDR_BITS = 24, ADDR_BITS = 24,
ADDR_MASK = ((1 << ADDR_BITS) - 1), ADDR_MASK = ((1 << ADDR_BITS) - 1),
ADDR_TYPE_MASK = ~ADDR_MASK, ADDR_TYPE_MASK = ~ADDR_MASK,
ADDR_TYPE_SELF = 0, ADDR_TYPE_STACK = 0,
ADDR_TYPE_CLASS = 1, ADDR_TYPE_CONSTANT = 1,
ADDR_TYPE_MEMBER = 2, ADDR_TYPE_MEMBER = 2,
ADDR_TYPE_CLASS_CONSTANT = 3, };
ADDR_TYPE_LOCAL_CONSTANT = 4,
ADDR_TYPE_STACK = 5, enum FixedAddresses {
ADDR_TYPE_STACK_VARIABLE = 6, ADDR_STACK_SELF = 0,
ADDR_TYPE_GLOBAL = 7, ADDR_STACK_CLASS = 1,
ADDR_TYPE_NAMED_GLOBAL = 8, ADDR_STACK_NIL = 2,
ADDR_TYPE_NIL = 9 ADDR_SELF = ADDR_STACK_SELF | (ADDR_TYPE_STACK << ADDR_BITS),
ADDR_CLASS = ADDR_STACK_CLASS | (ADDR_TYPE_STACK << ADDR_BITS),
ADDR_NIL = ADDR_STACK_NIL | (ADDR_TYPE_STACK << ADDR_BITS),
}; };
enum Instruction { enum Instruction {
@@ -462,7 +465,7 @@ private:
List<StackDebug> stack_debug; List<StackDebug> stack_debug;
_FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const; _FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const;
_FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const; _FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const;
friend class GDScriptLanguage; friend class GDScriptLanguage;
@@ -497,7 +500,6 @@ public:
#endif #endif
Vector<uint8_t> stack; Vector<uint8_t> stack;
int stack_size = 0; int stack_size = 0;
Variant self;
uint32_t alloca_size = 0; uint32_t alloca_size = 0;
int ip = 0; int ip = 0;
int line = 0; int line = 0;

View File

@@ -34,22 +34,22 @@
#include "core/os/os.h" #include "core/os/os.h"
#include "gdscript.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; int address = p_address & ADDR_MASK;
//sequential table (jump table generated by compiler) //sequential table (jump table generated by compiler)
switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) { switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) {
case ADDR_TYPE_SELF: { case ADDR_TYPE_STACK: {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (unlikely(!p_instance)) { ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
r_error = "Cannot access self without instance.";
return nullptr;
}
#endif #endif
return &self; return &p_stack[address];
} break; } break;
case ADDR_TYPE_CLASS: { case ADDR_TYPE_CONSTANT: {
return &static_ref; #ifdef DEBUG_ENABLED
ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
#endif
return &_constants_ptr[address];
} break; } break;
case ADDR_TYPE_MEMBER: { case ADDR_TYPE_MEMBER: {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
@@ -61,65 +61,6 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
//member indexing is O(1) //member indexing is O(1)
return &p_instance->members.write[address]; return &p_instance->members.write[address];
} break; } 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)."); 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_VECTOR3_ARRAY, \
&&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \ &&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
&&OPCODE_ITERATE_OBJECT, \ &&OPCODE_ITERATE_OBJECT, \
&&OPCODE_STORE_NAMED_GLOBAL, \
&&OPCODE_ASSERT, \ &&OPCODE_ASSERT, \
&&OPCODE_BREAKPOINT, \ &&OPCODE_BREAKPOINT, \
&&OPCODE_LINE, \ &&OPCODE_LINE, \
@@ -415,11 +357,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
r_err.error = Callable::CallError::CALL_OK; r_err.error = Callable::CallError::CALL_OK;
Variant self;
Variant static_ref;
Variant retvalue; Variant retvalue;
Variant *stack = nullptr; Variant *stack = nullptr;
Variant **instruction_args; Variant **instruction_args = nullptr;
const void **call_args_ptr = nullptr; const void **call_args_ptr = nullptr;
int defarg = 0; int defarg = 0;
@@ -444,7 +384,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
script = p_state->script; script = p_state->script;
p_instance = p_state->instance; p_instance = p_state->instance;
defarg = p_state->defarg; defarg = p_state->defarg;
self = p_state->self;
} else { } else {
if (p_argcount != _argument_count) { 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) { for (int i = 0; i < p_argcount; i++) {
stack = (Variant *)aptr; if (!argument_types[i].has_type) {
for (int i = 0; i < p_argcount; i++) { memnew_placement(&stack[i + 3], Variant(*p_args[i]));
if (!argument_types[i].has_type) { continue;
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;
} }
if (_instruction_args_size) { if (!argument_types[i].is_type(*p_args[i], true)) {
instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size]; r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
} else { r_err.argument = i;
instruction_args = nullptr; 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 { } else {
stack = nullptr;
instruction_args = nullptr; instruction_args = nullptr;
} }
if (p_instance) { if (p_instance) {
self = p_instance->owner; memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
script = p_instance->script.ptr(); script = p_instance->script.ptr();
} else { } else {
memnew_placement(&stack[ADDR_STACK_SELF], Variant);
script = _script; script = _script;
} }
} }
@@ -520,7 +453,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
call_args_ptr = nullptr; call_args_ptr = nullptr;
} }
static_ref = script; memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
String err_text; String err_text;
@@ -541,10 +474,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define CHECK_SPACE(m_space) \ #define CHECK_SPACE(m_space) \
GD_ERR_BREAK((ip + m_space) > _code_size) GD_ERR_BREAK((ip + m_space) > _code_size)
#define GET_VARIANT_PTR(m_v, m_code_ofs) \ #define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant *m_v; \ 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); \
if (unlikely(!m_v)) \ if (unlikely(!m_v)) \
OPCODE_BREAK; OPCODE_BREAK;
#else #else
@@ -552,7 +485,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define CHECK_SPACE(m_space) #define CHECK_SPACE(m_space)
#define GET_VARIANT_PTR(m_v, m_code_ofs) \ #define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant *m_v; \ 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 #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])); memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i]));
} }
gdfs->state.stack_size = _stack_size; gdfs->state.stack_size = _stack_size;
gdfs->state.self = self;
gdfs->state.alloca_size = alloca_size; gdfs->state.alloca_size = alloca_size;
gdfs->state.ip = ip + 2; gdfs->state.ip = ip + 2;
gdfs->state.line = line; gdfs->state.line = line;
@@ -3028,6 +2960,19 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} }
DISPATCH_OPCODE; 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) { OPCODE(OPCODE_ASSERT) {
CHECK_SPACE(3); CHECK_SPACE(3);