react-native-webgpu 0.10.1 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Package.swift +57 -102
- package/android/cpp/cpp-adapter.cpp +142 -1
- package/android/src/main/java/com/webgpu/WebGPUAPI.java +2 -0
- package/android/src/main/java/com/webgpu/WebGPUHardwareBufferView.java +278 -0
- package/android/src/main/java/com/webgpu/WebGPUView.java +49 -12
- package/cpp/jsi/JSICache.cpp +23 -0
- package/cpp/jsi/JSICache.h +28 -1
- package/cpp/jsi/NativeObject.h +86 -50
- package/cpp/rnwgpu/SurfaceRegistry.h +613 -0
- package/lib/commonjs/Canvas.js +1 -1
- package/lib/commonjs/Canvas.js.map +1 -1
- package/lib/module/Canvas.js +1 -1
- package/lib/module/Canvas.js.map +1 -1
- package/lib/typescript/react-native.config.d.ts +4 -0
- package/lib/typescript/react-native.config.d.ts.map +1 -0
- package/lib/typescript/src/Canvas.d.ts +6 -4
- package/lib/typescript/src/Canvas.d.ts.map +1 -1
- package/lib/typescript/src/WebGPUViewNativeComponent.d.ts +1 -1
- package/lib/typescript/src/WebGPUViewNativeComponent.d.ts.map +1 -1
- package/package.json +2 -1
- package/react-native-webgpu.podspec +8 -9
- package/react-native.config.js +6 -0
- package/src/Canvas.tsx +10 -5
- package/src/WebGPUViewNativeComponent.ts +1 -1
- package/android/src/main/java/com/webgpu/WebGPUAHBView.java +0 -298
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package com.webgpu;
|
|
2
2
|
|
|
3
3
|
import android.content.Context;
|
|
4
|
+
import android.os.Build;
|
|
4
5
|
import android.view.Surface;
|
|
5
6
|
import android.view.View;
|
|
6
7
|
|
|
@@ -10,12 +11,16 @@ import com.facebook.react.views.view.ReactViewGroup;
|
|
|
10
11
|
|
|
11
12
|
public class WebGPUView extends ReactViewGroup implements WebGPUAPI {
|
|
12
13
|
|
|
14
|
+
// Backing view kinds, see updateView().
|
|
15
|
+
private static final int KIND_SURFACE_VIEW = 0;
|
|
16
|
+
private static final int KIND_TEXTURE_VIEW = 1;
|
|
17
|
+
private static final int KIND_HARDWARE_BUFFER_VIEW = 2;
|
|
13
18
|
|
|
14
19
|
private int mContextId;
|
|
15
20
|
private boolean mOpaque = true;
|
|
16
21
|
private String mSurfaceType = "auto";
|
|
17
22
|
private boolean mZOrderOnTop = false;
|
|
18
|
-
private
|
|
23
|
+
private int mAppliedKind = -1;
|
|
19
24
|
private boolean mAppliedZOrderOnTop;
|
|
20
25
|
private WebGPUModule mModule;
|
|
21
26
|
private View mView = null;
|
|
@@ -46,35 +51,62 @@ public class WebGPUView extends ReactViewGroup implements WebGPUAPI {
|
|
|
46
51
|
mZOrderOnTop = value;
|
|
47
52
|
}
|
|
48
53
|
|
|
54
|
+
// Resolve the backing view from the props. "auto" picks SurfaceView for an
|
|
55
|
+
// opaque canvas and TextureView for a non-opaque one. WebGPUHardwareBufferView
|
|
56
|
+
// (a plain View drawing AHardwareBuffers inline, API 29+) is opt-in via
|
|
57
|
+
// surfaceType until it gets a runtime fallback to TextureView when the
|
|
58
|
+
// AHardwareBuffer import fails on a device; below API 29 the request itself
|
|
59
|
+
// falls back to TextureView.
|
|
60
|
+
private int resolveKind() {
|
|
61
|
+
if ("SurfaceView".equals(mSurfaceType)) {
|
|
62
|
+
return KIND_SURFACE_VIEW;
|
|
63
|
+
}
|
|
64
|
+
if ("TextureView".equals(mSurfaceType)) {
|
|
65
|
+
return KIND_TEXTURE_VIEW;
|
|
66
|
+
}
|
|
67
|
+
if ("HardwareBufferView".equals(mSurfaceType)) {
|
|
68
|
+
boolean hardwareBufferSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
|
|
69
|
+
return hardwareBufferSupported ? KIND_HARDWARE_BUFFER_VIEW : KIND_TEXTURE_VIEW;
|
|
70
|
+
}
|
|
71
|
+
return mOpaque ? KIND_SURFACE_VIEW : KIND_TEXTURE_VIEW;
|
|
72
|
+
}
|
|
73
|
+
|
|
49
74
|
// Apply the complete prop transaction once, after contextId and all rendering
|
|
50
75
|
// options have arrived. Only a change of backing view (or of zOrderOnTop,
|
|
51
76
|
// which a SurfaceView must know before it attaches) replaces the child;
|
|
52
77
|
// opacity is applied in place.
|
|
53
78
|
public void updateView() {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (mView == null || textureView != mAppliedTextureView
|
|
58
|
-
|| zOrderOnTop != mAppliedZOrderOnTop) {
|
|
79
|
+
int kind = resolveKind();
|
|
80
|
+
boolean zOrderOnTop = kind == KIND_SURFACE_VIEW && mZOrderOnTop;
|
|
81
|
+
if (mView == null || kind != mAppliedKind || zOrderOnTop != mAppliedZOrderOnTop) {
|
|
59
82
|
if (mView != null) {
|
|
60
83
|
removeView(mView);
|
|
61
84
|
}
|
|
62
|
-
|
|
85
|
+
mAppliedKind = kind;
|
|
63
86
|
mAppliedZOrderOnTop = zOrderOnTop;
|
|
64
87
|
Context ctx = getContext();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
88
|
+
switch (kind) {
|
|
89
|
+
case KIND_HARDWARE_BUFFER_VIEW:
|
|
90
|
+
mView = new WebGPUHardwareBufferView(ctx, this);
|
|
91
|
+
break;
|
|
92
|
+
case KIND_TEXTURE_VIEW:
|
|
93
|
+
mView = new WebGPUTextureView(ctx, this, mOpaque);
|
|
94
|
+
break;
|
|
95
|
+
default:
|
|
96
|
+
mView = new WebGPUSurfaceView(ctx, this, zOrderOnTop, mOpaque);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
68
99
|
addView(mView);
|
|
69
100
|
// ReactViewGroup.requestLayout() is a deliberate no-op, so addView outside
|
|
70
101
|
// the layout pass never lays the child out; do it by hand or the new view
|
|
71
102
|
// stays 0x0 and never gets a surface.
|
|
72
103
|
layoutChild();
|
|
73
|
-
} else if (
|
|
104
|
+
} else if (kind == KIND_TEXTURE_VIEW) {
|
|
74
105
|
((WebGPUTextureView) mView).setOpaque(mOpaque);
|
|
75
|
-
} else {
|
|
106
|
+
} else if (kind == KIND_SURFACE_VIEW) {
|
|
76
107
|
((WebGPUSurfaceView) mView).setOpaque(mOpaque);
|
|
77
108
|
}
|
|
109
|
+
// WebGPUHardwareBufferView always composites with alpha; opacity is a no-op.
|
|
78
110
|
}
|
|
79
111
|
|
|
80
112
|
private void layoutChild() {
|
|
@@ -110,6 +142,11 @@ public class WebGPUView extends ReactViewGroup implements WebGPUAPI {
|
|
|
110
142
|
switchToOffscreenSurface(mContextId);
|
|
111
143
|
}
|
|
112
144
|
|
|
145
|
+
@Override
|
|
146
|
+
public int getContextId() {
|
|
147
|
+
return mContextId;
|
|
148
|
+
}
|
|
149
|
+
|
|
113
150
|
/**
|
|
114
151
|
* Called from WebGPUViewManager.onDropViewInstance when React removes this
|
|
115
152
|
* view: the view dies with its Canvas, so it retires the registry entry.
|
package/cpp/jsi/JSICache.cpp
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "JSICache.h"
|
|
2
2
|
|
|
3
|
+
#include <algorithm>
|
|
3
4
|
#include <iterator>
|
|
4
5
|
#include <stdexcept>
|
|
5
6
|
#include <string>
|
|
@@ -94,4 +95,26 @@ jsi::Object &JSICache::setPrototype(PrototypeKey key, jsi::Object prototype) {
|
|
|
94
95
|
return it->second;
|
|
95
96
|
}
|
|
96
97
|
|
|
98
|
+
jsi::Value JSICache::lockWrapper(jsi::Runtime &runtime,
|
|
99
|
+
const void *nativeObject) {
|
|
100
|
+
auto it = _wrappers.find(nativeObject);
|
|
101
|
+
if (it == _wrappers.end()) {
|
|
102
|
+
return jsi::Value::undefined();
|
|
103
|
+
}
|
|
104
|
+
return it->second.lock(runtime);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
void JSICache::setWrapper(jsi::Runtime &runtime, const void *nativeObject,
|
|
108
|
+
const jsi::Object &wrapper) {
|
|
109
|
+
_wrappers.insert_or_assign(nativeObject, jsi::WeakObject(runtime, wrapper));
|
|
110
|
+
if (_wrappers.size() < _pruneWrappersAt) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
for (auto it = _wrappers.begin(); it != _wrappers.end();) {
|
|
114
|
+
it = it->second.lock(runtime).isUndefined() ? _wrappers.erase(it)
|
|
115
|
+
: std::next(it);
|
|
116
|
+
}
|
|
117
|
+
_pruneWrappersAt = std::max(kMinPruneWrappersAt, _wrappers.size() * 2);
|
|
118
|
+
}
|
|
119
|
+
|
|
97
120
|
} // namespace rnwgpu
|
package/cpp/jsi/JSICache.h
CHANGED
|
@@ -13,7 +13,8 @@ namespace jsi = facebook::jsi;
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Per-runtime store for JSI values that native code wants to keep across
|
|
16
|
-
* calls
|
|
16
|
+
* calls: the prototype object of every NativeObject class, and the JS
|
|
17
|
+
* wrapper of every native object that has one on the runtime.
|
|
17
18
|
*
|
|
18
19
|
* Ownership model (borrowed from react-native-nitro-modules' JSICache):
|
|
19
20
|
*
|
|
@@ -72,6 +73,26 @@ public:
|
|
|
72
73
|
*/
|
|
73
74
|
jsi::Object &setPrototype(PrototypeKey key, jsi::Object prototype);
|
|
74
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Returns the JS wrapper stored for `nativeObject` on this runtime, or
|
|
78
|
+
* undefined if none was stored or the wrapper has been collected.
|
|
79
|
+
*
|
|
80
|
+
* The key is the native object's address. A live wrapper keeps its native
|
|
81
|
+
* object alive (the object is the wrapper's NativeState), so as long as
|
|
82
|
+
* the entry locks it still belongs to that object. Once the wrapper has
|
|
83
|
+
* been collected the entry is stale and is skipped or replaced, so an
|
|
84
|
+
* address reused by a new object can never resolve to the old wrapper.
|
|
85
|
+
*/
|
|
86
|
+
jsi::Value lockWrapper(jsi::Runtime &runtime, const void *nativeObject);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Stores `wrapper` as the JS wrapper of `nativeObject` on this runtime.
|
|
90
|
+
* Only a weak reference is kept: the wrapper stays collectable, and the
|
|
91
|
+
* native object is released when it goes away.
|
|
92
|
+
*/
|
|
93
|
+
void setWrapper(jsi::Runtime &runtime, const void *nativeObject,
|
|
94
|
+
const jsi::Object &wrapper);
|
|
95
|
+
|
|
75
96
|
JSICache() = default;
|
|
76
97
|
~JSICache() override = default;
|
|
77
98
|
JSICache(const JSICache &) = delete;
|
|
@@ -81,6 +102,12 @@ private:
|
|
|
81
102
|
static std::shared_ptr<JSICache> getOrCreateOnGlobal(jsi::Runtime &runtime);
|
|
82
103
|
|
|
83
104
|
std::unordered_map<PrototypeKey, jsi::Object> _prototypes;
|
|
105
|
+
// Native object -> its wrapper on this runtime. Entries of collected
|
|
106
|
+
// wrappers are pruned in setWrapper once the map has doubled since the
|
|
107
|
+
// last pruning, so it stays proportional to the number of live wrappers.
|
|
108
|
+
std::unordered_map<const void *, jsi::WeakObject> _wrappers;
|
|
109
|
+
size_t _pruneWrappersAt = kMinPruneWrappersAt;
|
|
110
|
+
static constexpr size_t kMinPruneWrappersAt = 64;
|
|
84
111
|
|
|
85
112
|
// Runtime -> cache. Weak on purpose: the runtime's global owns the cache.
|
|
86
113
|
static std::mutex _registryMutex;
|
package/cpp/jsi/NativeObject.h
CHANGED
|
@@ -34,44 +34,51 @@ namespace jsi = facebook::jsi;
|
|
|
34
34
|
template <typename Derived> class NativeObject;
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Registry
|
|
38
|
-
*
|
|
39
|
-
*
|
|
37
|
+
* Registry mapping a NativeObject class brand (CLASS_NAME) to a reconstructor
|
|
38
|
+
* that rebuilds a fully functional JS object (prototype + native state) on
|
|
39
|
+
* any runtime. This is what lets BoxedWebGPUObject::unbox() bring objects to
|
|
40
|
+
* worklet runtimes.
|
|
40
41
|
*/
|
|
41
42
|
class NativeObjectRegistry {
|
|
42
43
|
public:
|
|
43
|
-
using
|
|
44
|
+
using Reconstructor = std::function<jsi::Value(
|
|
45
|
+
jsi::Runtime &, std::shared_ptr<jsi::NativeState>)>;
|
|
44
46
|
|
|
45
47
|
static NativeObjectRegistry &getInstance() {
|
|
46
48
|
static NativeObjectRegistry instance;
|
|
47
49
|
return instance;
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
void
|
|
52
|
+
void registerClass(const std::string &brand, Reconstructor reconstructor) {
|
|
51
53
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
52
|
-
if (
|
|
54
|
+
if (_reconstructors.count(brand) != 0) {
|
|
53
55
|
// The brand is the key unbox() uses to rebuild objects on worklet
|
|
54
56
|
// runtimes - a duplicate would let one class hijack another's unboxing.
|
|
55
57
|
throw std::runtime_error("Duplicate native object brand registered: " +
|
|
56
58
|
brand);
|
|
57
59
|
}
|
|
58
|
-
|
|
60
|
+
_reconstructors[brand] = std::move(reconstructor);
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
jsi::Value reconstruct(jsi::Runtime &runtime, const std::string &brand,
|
|
64
|
+
std::shared_ptr<jsi::NativeState> state) {
|
|
65
|
+
Reconstructor reconstructor;
|
|
66
|
+
{
|
|
67
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
68
|
+
auto it = _reconstructors.find(brand);
|
|
69
|
+
if (it == _reconstructors.end()) {
|
|
70
|
+
throw jsi::JSError(runtime,
|
|
71
|
+
"No native class registered for brand: " + brand);
|
|
72
|
+
}
|
|
73
|
+
reconstructor = it->second;
|
|
67
74
|
}
|
|
68
|
-
return
|
|
75
|
+
return reconstructor(runtime, std::move(state));
|
|
69
76
|
}
|
|
70
77
|
|
|
71
78
|
private:
|
|
72
79
|
NativeObjectRegistry() = default;
|
|
73
80
|
std::mutex _mutex;
|
|
74
|
-
std::unordered_map<std::string,
|
|
81
|
+
std::unordered_map<std::string, Reconstructor> _reconstructors;
|
|
75
82
|
};
|
|
76
83
|
|
|
77
84
|
/**
|
|
@@ -88,7 +95,8 @@ private:
|
|
|
88
95
|
* Usage pattern with registerCustomSerializable:
|
|
89
96
|
* - pack(): Call WebGPU.box(obj) to create a BoxedWebGPUObject (HostObject)
|
|
90
97
|
* - The HostObject is serialized by Worklets and transferred to UI runtime
|
|
91
|
-
* - unpack(): Call boxed.unbox() to get
|
|
98
|
+
* - unpack(): Call boxed.unbox() to get the object's wrapper on that runtime
|
|
99
|
+
* (cached per runtime, see NativeObject::create), prototype included
|
|
92
100
|
*
|
|
93
101
|
* This is similar to NitroModules.box()/unbox() pattern.
|
|
94
102
|
*/
|
|
@@ -101,37 +109,15 @@ public:
|
|
|
101
109
|
jsi::Value get(jsi::Runtime &runtime, const jsi::PropNameID &name) override {
|
|
102
110
|
auto propName = name.utf8(runtime);
|
|
103
111
|
if (propName == "unbox") {
|
|
112
|
+
auto state = _nativeState;
|
|
113
|
+
auto brand = _brand;
|
|
104
114
|
return jsi::Function::createFromHostFunction(
|
|
105
115
|
runtime, jsi::PropNameID::forUtf8(runtime, "unbox"), 0,
|
|
106
|
-
[
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (!ctor.isObject()) {
|
|
112
|
-
// Constructor doesn't exist on this runtime - install it
|
|
113
|
-
NativeObjectRegistry::getInstance().installPrototype(rt, _brand);
|
|
114
|
-
ctor = rt.global().getProperty(rt, _brand.c_str());
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Create a new object and attach the native state
|
|
118
|
-
jsi::Object obj(rt);
|
|
119
|
-
obj.setNativeState(rt, _nativeState);
|
|
120
|
-
|
|
121
|
-
// Set the prototype if constructor exists
|
|
122
|
-
if (ctor.isObject()) {
|
|
123
|
-
auto ctorObj = ctor.getObject(rt);
|
|
124
|
-
auto proto = ctorObj.getProperty(rt, "prototype");
|
|
125
|
-
if (proto.isObject()) {
|
|
126
|
-
auto objectCtor =
|
|
127
|
-
rt.global().getPropertyAsObject(rt, "Object");
|
|
128
|
-
auto setPrototypeOf =
|
|
129
|
-
objectCtor.getPropertyAsFunction(rt, "setPrototypeOf");
|
|
130
|
-
setPrototypeOf.call(rt, obj, proto);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return std::move(obj);
|
|
116
|
+
[state, brand](jsi::Runtime &rt, const jsi::Value & /*thisVal*/,
|
|
117
|
+
const jsi::Value * /*args*/,
|
|
118
|
+
size_t /*count*/) -> jsi::Value {
|
|
119
|
+
return NativeObjectRegistry::getInstance().reconstruct(rt, brand,
|
|
120
|
+
state);
|
|
135
121
|
});
|
|
136
122
|
}
|
|
137
123
|
if (propName == "__boxedWebGPU") {
|
|
@@ -305,15 +291,38 @@ public:
|
|
|
305
291
|
* created internally by the native code).
|
|
306
292
|
*
|
|
307
293
|
* Also registers this class with NativeObjectRegistry so that
|
|
308
|
-
* BoxedWebGPUObject::unbox() can
|
|
294
|
+
* BoxedWebGPUObject::unbox() can rebuild its objects on secondary runtimes.
|
|
309
295
|
*/
|
|
310
296
|
static void installConstructor(jsi::Runtime &runtime) {
|
|
311
|
-
// Register
|
|
297
|
+
// Register the reconstructor used by BoxedWebGPUObject::unbox() to
|
|
298
|
+
// rebuild this object (prototype + native state) on another runtime.
|
|
312
299
|
static std::once_flag registryFlag;
|
|
313
300
|
std::call_once(registryFlag, []() {
|
|
314
|
-
NativeObjectRegistry::getInstance().
|
|
301
|
+
NativeObjectRegistry::getInstance().registerClass(
|
|
315
302
|
Derived::CLASS_NAME,
|
|
316
|
-
[](jsi::Runtime &rt
|
|
303
|
+
[](jsi::Runtime &rt,
|
|
304
|
+
std::shared_ptr<jsi::NativeState> state) -> jsi::Value {
|
|
305
|
+
auto instance = std::dynamic_pointer_cast<Derived>(state);
|
|
306
|
+
if (instance == nullptr) {
|
|
307
|
+
throw jsi::JSError(rt, "Invalid boxed native object state");
|
|
308
|
+
}
|
|
309
|
+
// The constructor makes `instanceof` work on this runtime too.
|
|
310
|
+
if (!rt.global().hasProperty(rt, Derived::CLASS_NAME)) {
|
|
311
|
+
Derived::installConstructor(rt);
|
|
312
|
+
}
|
|
313
|
+
// Unboxing hands back the wrapper cached for the target runtime,
|
|
314
|
+
// creating it on first use. Keep the runtime the object was
|
|
315
|
+
// originally created on: async native code (GPUDevice error/lost
|
|
316
|
+
// events, GPUAdapter::requestDevice) delivers into the creation
|
|
317
|
+
// runtime, and rebinding it to a worklet runtime would invoke
|
|
318
|
+
// main-runtime jsi::Functions on the wrong runtime and thread.
|
|
319
|
+
auto *originalRuntime = instance->getCreationRuntime();
|
|
320
|
+
auto value = Derived::create(rt, instance);
|
|
321
|
+
if (originalRuntime != nullptr) {
|
|
322
|
+
instance->setCreationRuntime(originalRuntime);
|
|
323
|
+
}
|
|
324
|
+
return value;
|
|
325
|
+
});
|
|
317
326
|
});
|
|
318
327
|
|
|
319
328
|
installPrototype(runtime);
|
|
@@ -345,10 +354,36 @@ public:
|
|
|
345
354
|
}
|
|
346
355
|
|
|
347
356
|
/**
|
|
348
|
-
*
|
|
357
|
+
* Returns the JS wrapper of `instance` on `runtime`, creating it on first
|
|
358
|
+
* use.
|
|
359
|
+
*
|
|
360
|
+
* A native object has at most one live wrapper per runtime. The wrapper is
|
|
361
|
+
* cached (weakly, so it stays collectable) in the runtime's JSICache, and
|
|
362
|
+
* converting the same object again (returning it from another native
|
|
363
|
+
* call, unboxing it in a worklet on every frame, ...) hands back that
|
|
364
|
+
* wrapper instead of a new one. Each wrapper reports the native memory the
|
|
365
|
+
* object owns to the GC of its runtime through setExternalMemoryPressure,
|
|
366
|
+
* so the memory is charged exactly once per runtime that can reach the
|
|
367
|
+
* object, however often it is converted; charging every conversion would
|
|
368
|
+
* multiply the amount by the number of captures in a worklet until Hermes
|
|
369
|
+
* hit its max heap size. The hint is refreshed on every round trip for
|
|
370
|
+
* objects whose size changes after creation.
|
|
349
371
|
*/
|
|
350
372
|
static jsi::Value create(jsi::Runtime &runtime,
|
|
351
373
|
std::shared_ptr<Derived> instance) {
|
|
374
|
+
auto &cache = JSICache::get(runtime);
|
|
375
|
+
const void *key = instance.get();
|
|
376
|
+
|
|
377
|
+
auto existing = cache.lockWrapper(runtime, key);
|
|
378
|
+
if (existing.isObject()) {
|
|
379
|
+
auto pressure = instance->getMemoryPressure();
|
|
380
|
+
if (pressure > 0) {
|
|
381
|
+
existing.getObject(runtime).setExternalMemoryPressure(runtime,
|
|
382
|
+
pressure);
|
|
383
|
+
}
|
|
384
|
+
return existing;
|
|
385
|
+
}
|
|
386
|
+
|
|
352
387
|
installPrototype(runtime);
|
|
353
388
|
|
|
354
389
|
// Store creation runtime for logging etc.
|
|
@@ -374,6 +409,7 @@ public:
|
|
|
374
409
|
obj.setExternalMemoryPressure(runtime, pressure);
|
|
375
410
|
}
|
|
376
411
|
|
|
412
|
+
cache.setWrapper(runtime, key, obj);
|
|
377
413
|
return std::move(obj);
|
|
378
414
|
}
|
|
379
415
|
|