diff options
Diffstat (limited to 'modules/gdscript')
| -rw-r--r-- | modules/gdscript/gdscript.cpp | 4 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 18 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_byte_codegen.cpp | 62 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_byte_codegen.h | 1 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_cache.cpp | 4 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_codegen.h | 1 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 59 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_disassembler.cpp | 22 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_function.h | 3 | ||||
| -rw-r--r-- | modules/gdscript/gdscript_vm.cpp | 88 | ||||
| -rw-r--r-- | modules/gdscript/tests/test_gdscript.cpp | 2 |
11 files changed, 223 insertions, 41 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 859c1acde9..9206f4095a 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1045,10 +1045,10 @@ Error GDScript::load_source_code(const String &p_path) { ERR_FAIL_COND_V(err, err); } - int len = f->get_len(); + uint64_t len = f->get_len(); sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); - int r = f->get_buffer(w, len); + uint64_t r = f->get_buffer(w, len); f->close(); memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 17ae52f3ab..7b04959227 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2078,9 +2078,23 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa mark_node_unsafe(p_call); return; } - reduce_expression(subscript->base); + if (subscript->attribute == nullptr) { + // Invalid call. Error already sent in parser. + p_call->set_datatype(call_type); + mark_node_unsafe(p_call); + return; + } - base_type = subscript->base->get_datatype(); + GDScriptParser::IdentifierNode *base_id = nullptr; + if (subscript->base->type == GDScriptParser::Node::IDENTIFIER) { + base_id = static_cast<GDScriptParser::IdentifierNode *>(subscript->base); + } + if (base_id && GDScriptParser::get_builtin_type(base_id->name) < Variant::VARIANT_MAX) { + base_type = make_builtin_meta_type(GDScriptParser::get_builtin_type(base_id->name)); + } else { + reduce_expression(subscript->base); + base_type = subscript->base->get_datatype(); + } } else { // Invalid call. Error already sent in parser. // TODO: Could check if Callable here too. diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 0da99ccee3..ea34a2ca2d 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -129,12 +129,6 @@ uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type int idx = temporaries.size(); pool.push_back(idx); temporaries.push_back(new_temp); - - // First time using this, so adjust to the proper type. - if (temp_type != Variant::NIL) { - Address addr(Address::TEMPORARY, idx, p_type); - write_type_adjust(addr, temp_type); - } } int slot = pool.front()->get(); pool.pop_front(); @@ -189,8 +183,12 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() { append(GDScriptFunction::OPCODE_END, 0); for (int i = 0; i < temporaries.size(); i++) { + int stack_index = i + max_locals + RESERVED_STACK; for (int j = 0; j < temporaries[i].bytecode_indices.size(); j++) { - opcodes.write[temporaries[i].bytecode_indices[j]] = (i + max_locals + RESERVED_STACK) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); + opcodes.write[temporaries[i].bytecode_indices[j]] = stack_index | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); + } + if (temporaries[i].type != Variant::NIL) { + function->temporary_slots[stack_index] = temporaries[i].type; } } @@ -1017,6 +1015,56 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, append(Variant::get_validated_builtin_method(p_type, p_method)); } +void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) { + bool is_validated = false; + + // Check if all types are correct. + if (Variant::is_builtin_method_vararg(p_type, p_method)) { + is_validated = true; // Vararg works fine with any argument, since they can be any type. + } else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) { + bool all_types_exact = true; + for (int i = 0; i < p_arguments.size(); i++) { + if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_builtin_method_argument_type(p_type, p_method, i))) { + all_types_exact = false; + break; + } + } + + is_validated = all_types_exact; + } + + if (!is_validated) { + // Perform regular call. + append(GDScriptFunction::OPCODE_CALL_BUILTIN_STATIC, p_arguments.size() + 1); + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + append(p_target); + append(p_type); + append(p_method); + append(p_arguments.size()); + return; + } + + if (p_target.mode == Address::TEMPORARY) { + Variant::Type result_type = Variant::get_builtin_method_return_type(p_type, p_method); + Variant::Type temp_type = temporaries[p_target.address].type; + if (result_type != temp_type) { + write_type_adjust(p_target, result_type); + } + } + + append(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size()); + + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + append(Address()); // No base since it's static. + append(p_target); + append(p_arguments.size()); + append(Variant::get_validated_builtin_method(p_type, p_method)); +} + 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++) { diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index c060476f39..f8c05fea83 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -461,6 +461,7 @@ public: virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) override; virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) override; virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override; + 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_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; diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 113d36be98..6aa76703f1 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -153,9 +153,9 @@ String GDScriptCache::get_source_code(const String &p_path) { ERR_FAIL_COND_V(err, ""); } - int len = f->get_len(); + uint64_t len = f->get_len(); source_file.resize(len + 1); - int r = f->get_buffer(source_file.ptrw(), len); + uint64_t r = f->get_buffer(source_file.ptrw(), len); f->close(); ERR_FAIL_COND_V(r != len, ""); source_file.write[len] = 0; diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index ae9a8ede5e..399c9d6de7 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -122,6 +122,7 @@ public: virtual void write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) = 0; virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) = 0; virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0; + 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_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; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 37ce8ae2cb..f495b0d787 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -537,39 +537,44 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee); if (subscript->is_attribute) { - GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base); - if (r_error) { - return GDScriptCodeGenerator::Address(); - } - 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; + // May be static built-in method call. + if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) { + gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments); + } else { + GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base); + if (r_error) { + return GDScriptCodeGenerator::Address(); } - 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); + 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 { - // Not exact arguments, but still can use method bind call. - gen->write_call_method_bind(result, base, method, arguments); + 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 if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) { + gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments); } else { gen->write_call(result, base, call->function_name, arguments); } - } else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) { - gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments); - } else { - gen->write_call(result, base, call->function_name, arguments); - } - if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) { - gen->pop_temporary(); + if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + gen->pop_temporary(); + } } } else { _set_error("Cannot call something that isn't a function.", call->callee); diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index 789af57b4c..8a6ac04539 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -542,6 +542,28 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr = 5 + argc; } break; + case OPCODE_CALL_BUILTIN_STATIC: { + Variant::Type type = (Variant::Type)_code_ptr[ip + 1 + instr_var_args]; + int argc = _code_ptr[ip + 3 + instr_var_args]; + + text += "call built-in method static "; + text += DADDR(1 + argc); + text += " = "; + text += Variant::get_type_name(type); + text += "."; + text += _global_names_ptr[_code_ptr[ip + 2 + instr_var_args]].operator String(); + 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) "; diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 70b62ced6d..26b8809337 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -263,6 +263,7 @@ public: OPCODE_CALL_SELF_BASE, OPCODE_CALL_METHOD_BIND, OPCODE_CALL_METHOD_BIND_RET, + OPCODE_CALL_BUILTIN_STATIC, // ptrcall have one instruction per return type. OPCODE_CALL_PTRCALL_NO_RETURN, OPCODE_CALL_PTRCALL_BOOL, @@ -496,6 +497,8 @@ private: Vector<GDScriptDataType> argument_types; GDScriptDataType return_type; + Map<int, Variant::Type> temporary_slots; + #ifdef TOOLS_ENABLED Vector<StringName> arg_names; Vector<Variant> default_arg_values; diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 4757ec6ca9..d9fc54c9d4 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -152,6 +152,44 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const return err_text; } +void (*type_init_function_table[])(Variant *) = { + nullptr, // NIL (shouldn't be called). + &VariantInitializer<bool>::init, // BOOL. + &VariantInitializer<int64_t>::init, // INT. + &VariantInitializer<double>::init, // FLOAT. + &VariantInitializer<String>::init, // STRING. + &VariantInitializer<Vector2>::init, // VECTOR2. + &VariantInitializer<Vector2i>::init, // VECTOR2I. + &VariantInitializer<Rect2>::init, // RECT2. + &VariantInitializer<Rect2i>::init, // RECT2I. + &VariantInitializer<Vector3>::init, // VECTOR3. + &VariantInitializer<Vector3i>::init, // VECTOR3I. + &VariantInitializer<Transform2D>::init, // TRANSFORM2D. + &VariantInitializer<Plane>::init, // PLANE. + &VariantInitializer<Quat>::init, // QUAT. + &VariantInitializer<AABB>::init, // AABB. + &VariantInitializer<Basis>::init, // BASIS. + &VariantInitializer<Transform>::init, // TRANSFORM. + &VariantInitializer<Color>::init, // COLOR. + &VariantInitializer<StringName>::init, // STRING_NAME. + &VariantInitializer<NodePath>::init, // NODE_PATH. + &VariantInitializer<RID>::init, // RID. + &VariantTypeAdjust<Object *>::adjust, // OBJECT. + &VariantInitializer<Callable>::init, // CALLABLE. + &VariantInitializer<Signal>::init, // SIGNAL. + &VariantInitializer<Dictionary>::init, // DICTIONARY. + &VariantInitializer<Array>::init, // ARRAY. + &VariantInitializer<PackedByteArray>::init, // PACKED_BYTE_ARRAY. + &VariantInitializer<PackedInt32Array>::init, // PACKED_INT32_ARRAY. + &VariantInitializer<PackedInt64Array>::init, // PACKED_INT64_ARRAY. + &VariantInitializer<PackedFloat32Array>::init, // PACKED_FLOAT32_ARRAY. + &VariantInitializer<PackedFloat64Array>::init, // PACKED_FLOAT64_ARRAY. + &VariantInitializer<PackedStringArray>::init, // PACKED_STRING_ARRAY. + &VariantInitializer<PackedVector2Array>::init, // PACKED_VECTOR2_ARRAY. + &VariantInitializer<PackedVector3Array>::init, // PACKED_VECTOR3_ARRAY. + &VariantInitializer<PackedColorArray>::init, // PACKED_COLOR_ARRAY. +}; + #if defined(__GNUC__) #define OPCODES_TABLE \ static const void *switch_table_ops[] = { \ @@ -196,6 +234,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const &&OPCODE_CALL_SELF_BASE, \ &&OPCODE_CALL_METHOD_BIND, \ &&OPCODE_CALL_METHOD_BIND_RET, \ + &&OPCODE_CALL_BUILTIN_STATIC, \ &&OPCODE_CALL_PTRCALL_NO_RETURN, \ &&OPCODE_CALL_PTRCALL_BOOL, \ &&OPCODE_CALL_PTRCALL_INT, \ @@ -491,6 +530,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script)); + for (const Map<int, Variant::Type>::Element *E = temporary_slots.front(); E; E = E->next()) { + type_init_function_table[E->get()](&stack[E->key()]); + } + String err_text; #ifdef DEBUG_ENABLED @@ -1573,6 +1616,51 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_CALL_BUILTIN_STATIC) { + CHECK_SPACE(4 + instr_arg_count); + + ip += instr_arg_count; + + GD_ERR_BREAK(_code_ptr[ip + 1] < 0 || _code_ptr[ip + 1] >= Variant::VARIANT_MAX); + Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 1]; + + int methodname_idx = _code_ptr[ip + 2]; + GD_ERR_BREAK(methodname_idx < 0 || methodname_idx >= _global_names_count); + const StringName *methodname = &_global_names_ptr[methodname_idx]; + + int argc = _code_ptr[ip + 3]; + GD_ERR_BREAK(argc < 0); + + GET_INSTRUCTION_ARG(ret, argc); + + const Variant **argptrs = const_cast<const Variant **>(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; + Variant::call_static(builtin_type, *methodname, argptrs, argc, *ret, 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) { + err_text = _get_call_error(err, "static function '" + methodname->operator String() + "' in type '" + Variant::get_type_name(builtin_type) + "'", argptrs); + OPCODE_BREAK; + } +#endif + + ip += 4; + } + DISPATCH_OPCODE; + #ifdef DEBUG_ENABLED #define OPCODE_CALL_PTR(m_type) \ OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \ diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index 36da64bbaa..8ad5cdacad 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -215,7 +215,7 @@ void test(TestType p_type) { init_language(fa->get_path_absolute().get_base_dir()); Vector<uint8_t> buf; - int flen = fa->get_len(); + uint64_t flen = fa->get_len(); buf.resize(fa->get_len() + 1); fa->get_buffer(buf.ptrw(), flen); buf.write[flen] = 0; |