Skip to content

Commit 45d8e74

Browse files
Merge branch 'main' into daylily-zeleen/implement-reload_scripts-for-debugging
2 parents 1d860c3 + c542321 commit 45d8e74

5 files changed

Lines changed: 77 additions & 27 deletions

File tree

SCsub

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ if quickjs_support is None and jsc_support is None and is_library_supported(v8_p
184184
download_dependency("lws", deps_lws_version, "lws")
185185

186186
v8_support = validate_library_support(v8_prebuilt_libs) if quickjs_support is None else None
187-
lws_support = validate_library_support(lws_prebuilt_libs) if v8_support is None else None
187+
lws_support = validate_library_support(lws_prebuilt_libs) if v8_support is not None else None
188188

189189
jsb_defines = [
190190
CompileDefines("JSB_USE_TYPESCRIPT", 1 if env["use_typescript"] else 0),

bridge/jsb_environment.cpp

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ namespace jsb
542542
v8::Isolate::Scope isolate_scope(isolate_);
543543
v8::HandleScope handle_scope(isolate_);
544544
const v8::Local<v8::Context> context = context_.Get(isolate_);
545+
v8::Context::Scope context_scope(context);
545546

546547
for (const Message& message : messages)
547548
{
@@ -639,7 +640,7 @@ namespace jsb
639640
//TODO 0. HOW TO HANDLE COMPLICATED SITUATIONS? SUCH AS NESTED OBJECTS?
640641
jsb_nop();
641642

642-
transfer_in(*p_data);
643+
transfer_in(p_context, *p_data);
643644

644645
// call 'ontransfer'
645646
{
@@ -681,6 +682,13 @@ namespace jsb
681682
v8::Local<v8::Value> value;
682683
if (p_message)
683684
{
685+
const std::vector<TransferData>& transfers = p_message->get_transfers();
686+
687+
for (const auto& transfer : transfers)
688+
{
689+
p_env->transfer_in(p_context, transfer);
690+
}
691+
684692
#if JSB_WITH_V8
685693
Serialization::VariantDeserializerDelegate delegate(p_env, p_message->get_transfers());
686694
v8::ValueDeserializer deserializer(isolate, p_message->get_buffer().ptr(), p_message->get_buffer().size(), &delegate);
@@ -952,6 +960,8 @@ namespace jsb
952960
// hold it in a local variable to avoid gc too early
953961
v8::Global<v8::Object> obj_ref = std::move(object_handle->ref_);
954962

963+
// TODO: Look into if we ought to be calling obj->free_instance_binding(this)
964+
955965
//TODO do not clear the internal field if calling from JS GC
956966
// if (p_finalize != FinalizationType::None)
957967
// {
@@ -1963,10 +1973,11 @@ namespace jsb
19631973
return _call(isolate, context, js_func.object_.Get(isolate), v8::Undefined(isolate), p_args, p_argcount, r_error);
19641974
}
19651975

1966-
void Environment::transfer_out(NativeObjectID p_worker_handle_id, int transfer_index, const Variant& p_variant, TransferData& r_transfer_data)
1976+
void Environment::prepare_transfer_out(NativeObjectID p_worker_handle_id, int transfer_index, const Variant& p_variant, TransferData& r_transfer_data)
19671977
{
19681978
r_transfer_data.source_worker_id = p_worker_handle_id;
19691979
r_transfer_data.transfer_index = transfer_index;
1980+
r_transfer_data.variant = p_variant;
19701981

19711982
if (p_variant.get_type() == Variant::OBJECT)
19721983
{
@@ -1981,22 +1992,28 @@ namespace jsb
19811992

19821993
script_instance->get_property_state(r_transfer_data.state);
19831994
r_transfer_data.script_path = script->get_path();
1984-
1985-
obj->set_script_instance(nullptr);
19861995
}
1996+
}
1997+
}
1998+
1999+
void Environment::finalize_transfer_out(const TransferData& p_transfer_data)
2000+
{
2001+
const Variant& variant = p_transfer_data.variant;
19872002

2003+
if (variant.get_type() == Variant::OBJECT)
2004+
{
2005+
Object* obj = variant;
2006+
obj->set_script_instance(nullptr);
19882007
free_object(obj, FinalizationType::None);
19892008
}
19902009

19912010
// For now, we don't do anything special with variants since Godot's variant types are thread safe and use
19922011
// copy-on-write semantics. Technically, it may be advantageous for us to (in future?) clear the variant in the
19932012
// source environment since Godot has optimizations in place that will skip reallocation of the underlying data
19942013
// upon mutation if there's a single reference to that data.
1995-
1996-
r_transfer_data.variant = p_variant;
19972014
}
19982015

1999-
void Environment::transfer_in(const TransferData& p_data)
2016+
void Environment::transfer_in(const v8::Local<v8::Context>& p_context, const TransferData& p_data)
20002017
{
20012018
if (p_data.variant.get_type() == Variant::Type::OBJECT)
20022019
{
@@ -2009,21 +2026,38 @@ namespace jsb
20092026
return;
20102027
}
20112028

2012-
// restore the object state if it's a GodotJSScript
2029+
jsb_checkf(!object_db_.has_object(instance), "transferred in an object already registered in the environment");
2030+
2031+
if (!object_db_.has_object(instance))
2032+
{
2033+
v8::Local<v8::Object> obj;
2034+
jsb_check(TypeConvert::gd_obj_to_js(isolate_, p_context, instance, obj));
2035+
2036+
if (instance->is_ref_counted())
2037+
{
2038+
RefCounted *reference = static_cast<RefCounted *>(instance);
2039+
2040+
if (reference->unreference())
2041+
{
2042+
// Uh, we really shouldn't end up here. This can only occur if another thread is doing something it
2043+
// really shouldn't be doing. I guess we don't want to be responsible for a leak, but this is bad.
2044+
memdelete(reference);
2045+
JSB_LOG(Error, "transferred object unexpectedly freed: %d", (uint64_t) object_id);
2046+
return;
2047+
}
2048+
}
2049+
}
2050+
20132051
if (!p_data.script_path.is_empty())
20142052
{
2015-
// 1. create a script and script instance
2016-
// 2. attach the script & script instance to the object
2017-
const Ref<GodotJSScript> script = ResourceLoader::load(p_data.script_path);
2018-
jsb_check(script.is_valid());
2019-
jsb_unused(script->can_instantiate());
2020-
ScriptInstance* script_instance = script->instance_construct(instance, false);
2021-
jsb_check(script_instance);
2053+
ScriptInstance *script_instance = instance->get_script_instance();
20222054

2023-
// 3. restore the object state
2024-
for (const Pair<StringName, Variant>& pair : p_data.state)
2055+
if (script_instance)
20252056
{
2026-
script_instance->set(pair.first, pair.second);
2057+
for (const Pair<StringName, Variant>& pair : p_data.state)
2058+
{
2059+
script_instance->set(pair.first, pair.second);
2060+
}
20272061
}
20282062
}
20292063
}
@@ -2034,7 +2068,8 @@ namespace jsb
20342068
if (p_variant.get_type() == Variant::OBJECT)
20352069
{
20362070
TransferData* transfer_data = memnew(TransferData);
2037-
p_from->transfer_out(p_worker_handle_id, 0, p_variant, *transfer_data);
2071+
p_from->prepare_transfer_out(p_worker_handle_id, 0, p_variant, *transfer_data);
2072+
p_from->finalize_transfer_out(*transfer_data);
20382073
p_to->add_async_call(AsyncCall::TYPE_TRANSFER_, transfer_data);
20392074
}
20402075
else

bridge/jsb_environment.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,9 @@ namespace jsb
322322
*/
323323
Variant call_script_method(ScriptClassID p_script_class_id, NativeObjectID p_object_id, const StringName& p_method, const Variant** p_argv, int p_argc, Callable::CallError& r_error);
324324

325-
void transfer_out(NativeObjectID p_worker_handle_id, int transfer_index, const Variant& p_variant, TransferData& r_transfer_data);
326-
void transfer_in(const TransferData& p_data);
325+
void prepare_transfer_out(NativeObjectID p_worker_handle_id, int transfer_index, const Variant& p_variant, TransferData& r_transfer_data);
326+
void finalize_transfer_out(const TransferData& p_data);
327+
void transfer_in(const v8::Local<v8::Context>& p_context, const TransferData& p_data);
327328

328329
// [EXPERIMENTAL] transfer object between environments.
329330
// call this method of the source environment in the source environment thread.

bridge/jsb_object_bindings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ namespace jsb
355355
// prepare argv
356356
const int method_argc = method_bind->get_argument_count();
357357
const bool method_is_vararg = method_bind->is_vararg();
358+
358359
if (!internal::VariantUtil::check_argc(method_is_vararg, argc, method_bind->get_default_argument_count(), method_argc))
359360
{
360361
const String error_message = jsb_errorf("Failed to call: %s. %d arguments are required", method_bind->get_name(), method_argc - method_bind->get_default_argument_count());

bridge/jsb_worker.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ namespace jsb
130130
v8::Isolate::Scope isolate_scope(isolate);
131131
v8::HandleScope handle_scope(isolate);
132132
const v8::Local<v8::Context> context = env->get_context();
133+
v8::Context::Scope context_scope(context);
133134
const v8::Local<v8::Object> context_obj = context_obj_handle.Get(isolate);
134135

135136
for (const WorkerMessage& message : messages)
@@ -240,7 +241,7 @@ namespace jsb
240241

241242
for (const auto& transfer : p_message.get_transfers())
242243
{
243-
p_env->transfer_in(transfer);
244+
p_env->transfer_in(p_context, transfer);
244245
}
245246
}
246247

@@ -685,21 +686,28 @@ namespace jsb
685686

686687
Variant variant;
687688

688-
if (!TypeConvert::js_to_gd_var(isolate, context, item.As<v8::Object>(), Variant::Type::ARRAY, variant))
689+
if (!TypeConvert::js_to_gd_var(isolate, context, item.As<v8::Object>(), variant))
689690
{
690691
jsb_throw(isolate, "transfer list must contain Godot object/variant types only");
691692
return {nullptr, 0};
692693
}
693694

694695
TransferData transfer_data;
695-
from_env->transfer_out(NativeObjectID::none(), transfers.size(), variant, transfer_data);
696+
from_env->prepare_transfer_out(NativeObjectID::none(), transfers.size(), variant, transfer_data);
696697
transfers.insert(variant, transfer_data);
697698
}
698699
}
699700
else
700701
{
701702
Variant transfer_var;
702-
if (!TypeConvert::js_to_gd_var(isolate, context, transfer_arg.As<v8::Object>(), Variant::Type::ARRAY, transfer_var))
703+
704+
if (!TypeConvert::js_to_gd_var(isolate, context, transfer_arg.As<v8::Object>(), Variant::Type::OBJECT, transfer_var))
705+
{
706+
jsb_throw(isolate, "transfer list must be an array");
707+
return std::pair<uint8_t*, size_t>();
708+
}
709+
710+
if (!transfer_var.is_array())
703711
{
704712
jsb_throw(isolate, "transfer list must be an array");
705713
return std::pair<uint8_t*, size_t>();
@@ -711,7 +719,7 @@ namespace jsb
711719
{
712720
Variant& variant = transfer_arr[i];
713721
TransferData transfer_data;
714-
from_env->transfer_out(NativeObjectID::none(), i, variant, transfer_data);
722+
from_env->prepare_transfer_out(NativeObjectID::none(), i, variant, transfer_data);
715723
transfers.insert(variant, transfer_data);
716724
}
717725
}
@@ -736,6 +744,11 @@ namespace jsb
736744
return {nullptr, 0};
737745
}
738746

747+
for (const auto& entry : transfers)
748+
{
749+
from_env->finalize_transfer_out(entry.value);
750+
}
751+
739752
return serializer.Release();
740753
}
741754
}

0 commit comments

Comments
 (0)