@@ -311,160 +311,144 @@ class String {
311311
312312class Value {
313313 public:
314- Value ()
315- : storage_ (
316- std::make_shared<jscengine::ValueStorage>(jscengine::ValueStorage::Kind::Undefined)) {}
314+ Value () : kind_ (jscengine::ValueStorage::Kind::Undefined) {}
317315
318- Value (bool value)
319- : storage_ (std::make_shared<jscengine::ValueStorage>(jscengine::ValueStorage::Kind::Bool)) {
320- storage_->boolValue = value;
321- }
316+ Value (bool value) : kind_ (jscengine::ValueStorage::Kind::Bool), boolValue_ (value) {}
322317
323- Value (double value)
324- : storage_ (std::make_shared<jscengine::ValueStorage>(jscengine::ValueStorage::Kind::Number)) {
325- storage_->numberValue = value;
326- }
318+ Value (double value) : kind_ (jscengine::ValueStorage::Kind::Number), numberValue_ (value) {}
327319
328320 Value (int value) : Value (static_cast<double >(value)) {}
329321 Value (uint32_t value) : Value (static_cast<double >(value)) {}
330322
331323 Value (Runtime& runtime, const Value& value) {
332- if (value.storage_ -> kind == jscengine::ValueStorage::Kind::JSCBorrowed) {
333- storage_ =
334- std::make_shared<jscengine::ValueStorage>(jscengine::ValueStorage::Kind::JSC );
324+ if (value.kind_ == jscengine::ValueStorage::Kind::JSCBorrowed) {
325+ // Promote borrowed to owned
326+ storage_ = std::make_shared<jscengine::ValueStorage>(jscengine::ValueStorage::Kind::JSC );
335327 storage_->context = runtime.context ();
336- storage_->value = value.storage_ ->value != nullptr
337- ? value.storage_ ->value
338- : JSValueMakeUndefined (runtime.context ());
328+ storage_->value = value.borrowedValue_ != nullptr ? value.borrowedValue_
329+ : JSValueMakeUndefined (runtime.context ());
339330 JSValueProtect (runtime.context (), storage_->value );
331+ kind_ = jscengine::ValueStorage::Kind::JSC ;
340332 return ;
341333 }
334+ kind_ = value.kind_ ;
335+ boolValue_ = value.boolValue_ ;
336+ numberValue_ = value.numberValue_ ;
337+ borrowedContext_ = value.borrowedContext_ ;
338+ borrowedValue_ = value.borrowedValue_ ;
342339 storage_ = value.storage_ ;
343340 }
344- Value (Runtime& runtime, Value&& value) : storage_ (std::move (value.storage_ )) {}
345- Value (Runtime& runtime, const String& value) : storage_ (value.storage_ ) {}
341+ Value (Runtime& runtime, Value&& value)
342+ : kind_ (value.kind_ ),
343+ boolValue_ (value.boolValue_ ),
344+ numberValue_ (value.numberValue_ ),
345+ borrowedContext_ (value.borrowedContext_ ),
346+ borrowedValue_ (value.borrowedValue_ ),
347+ storage_ (std::move (value.storage_ )) {}
348+ Value (Runtime& runtime, const String& value);
346349 Value (Runtime& runtime, const Object& object);
347350 Value (Runtime& runtime, const Function& function);
348351 Value (Runtime& runtime, const Array& array);
349352 Value (Runtime& runtime, const ArrayBuffer& arrayBuffer);
350353 Value (Runtime& runtime, const BigInt& bigint);
351354 Value (Runtime& runtime, JSValueRef value)
352- : storage_ (std::make_shared<jscengine::ValueStorage>(jscengine::ValueStorage::Kind::JSC )) {
355+ : kind_ (jscengine::ValueStorage::Kind::JSC ),
356+ storage_ (std::make_shared<jscengine::ValueStorage>(jscengine::ValueStorage::Kind::JSC )) {
353357 storage_->context = runtime.context ();
354358 storage_->value = value != nullptr ? value : JSValueMakeUndefined (runtime.context ());
355359 JSValueProtect (runtime.context (), storage_->value );
356360 }
357361
358362 static Value borrowed (Runtime& runtime, JSValueRef value) {
359363 Value result;
360- result.storage_ -> kind = jscengine::ValueStorage::Kind::JSCBorrowed;
361- result.storage_ -> context = runtime.context ();
362- result.storage_ -> value = value != nullptr ? value : JSValueMakeUndefined (runtime.context ());
364+ result.kind_ = jscengine::ValueStorage::Kind::JSCBorrowed;
365+ result.borrowedContext_ = runtime.context ();
366+ result.borrowedValue_ = value != nullptr ? value : JSValueMakeUndefined (runtime.context ());
363367 return result;
364368 }
365369
366370 static Value undefined () { return Value (); }
367371 static Value null () {
368372 Value value;
369- value.storage_ = std::make_shared< jscengine::ValueStorage>(jscengine::ValueStorage:: Kind::Null) ;
373+ value.kind_ = jscengine::ValueStorage:: Kind::Null;
370374 return value;
371375 }
372376
373377 bool isUndefined () const {
374- return storage_->kind == jscengine::ValueStorage::Kind::Undefined ||
375- (storage_->kind == jscengine::ValueStorage::Kind::JSC &&
376- JSValueIsUndefined (storage_->context , storage_->value )) ||
377- (storage_->kind == jscengine::ValueStorage::Kind::JSCBorrowed &&
378- JSValueIsUndefined (storage_->context , storage_->value ));
378+ return kind_ == jscengine::ValueStorage::Kind::Undefined ||
379+ (isJSC () && JSValueIsUndefined (jscContext (), jscValue ()));
379380 }
380381 bool isNull () const {
381- return storage_->kind == jscengine::ValueStorage::Kind::Null ||
382- (storage_->kind == jscengine::ValueStorage::Kind::JSC &&
383- JSValueIsNull (storage_->context , storage_->value )) ||
384- (storage_->kind == jscengine::ValueStorage::Kind::JSCBorrowed &&
385- JSValueIsNull (storage_->context , storage_->value ));
382+ return kind_ == jscengine::ValueStorage::Kind::Null ||
383+ (isJSC () && JSValueIsNull (jscContext (), jscValue ()));
386384 }
387385 bool isBool () const {
388- return storage_->kind == jscengine::ValueStorage::Kind::Bool ||
389- (storage_->kind == jscengine::ValueStorage::Kind::JSC &&
390- JSValueIsBoolean (storage_->context , storage_->value )) ||
391- (storage_->kind == jscengine::ValueStorage::Kind::JSCBorrowed &&
392- JSValueIsBoolean (storage_->context , storage_->value ));
386+ return kind_ == jscengine::ValueStorage::Kind::Bool ||
387+ (isJSC () && JSValueIsBoolean (jscContext (), jscValue ()));
393388 }
394389 bool getBool () const {
395- if (storage_->kind == jscengine::ValueStorage::Kind::Bool) {
396- return storage_->boolValue ;
397- }
398- if (storage_->kind == jscengine::ValueStorage::Kind::JSC ||
399- storage_->kind == jscengine::ValueStorage::Kind::JSCBorrowed) {
400- return JSValueToBoolean (storage_->context , storage_->value );
390+ if (kind_ == jscengine::ValueStorage::Kind::Bool) {
391+ return boolValue_;
401392 }
402- return false ;
393+ return isJSC () && JSValueToBoolean ( jscContext (), jscValue ()) ;
403394 }
404395 bool isNumber () const {
405- return storage_->kind == jscengine::ValueStorage::Kind::Number ||
406- (storage_->kind == jscengine::ValueStorage::Kind::JSC &&
407- JSValueIsNumber (storage_->context , storage_->value )) ||
408- (storage_->kind == jscengine::ValueStorage::Kind::JSCBorrowed &&
409- JSValueIsNumber (storage_->context , storage_->value ));
396+ return kind_ == jscengine::ValueStorage::Kind::Number ||
397+ (isJSC () && JSValueIsNumber (jscContext (), jscValue ()));
410398 }
411399 double getNumber () const {
412- if (storage_->kind == jscengine::ValueStorage::Kind::Number) {
413- return storage_->numberValue ;
414- }
415- if (storage_->kind == jscengine::ValueStorage::Kind::JSC ||
416- storage_->kind == jscengine::ValueStorage::Kind::JSCBorrowed) {
417- return JSValueToNumber (storage_->context , storage_->value , nullptr );
400+ if (kind_ == jscengine::ValueStorage::Kind::Number) {
401+ return numberValue_;
418402 }
419- return 0 ;
403+ return isJSC () ? JSValueToNumber ( jscContext (), jscValue (), nullptr ) : 0 ;
420404 }
421405
422- bool isObject () const {
423- return (storage_->kind == jscengine::ValueStorage::Kind::JSC ||
424- storage_->kind == jscengine::ValueStorage::Kind::JSCBorrowed) &&
425- JSValueIsObject (storage_->context , storage_->value );
426- }
427- bool isString () const {
428- return (storage_->kind == jscengine::ValueStorage::Kind::JSC ||
429- storage_->kind == jscengine::ValueStorage::Kind::JSCBorrowed) &&
430- JSValueIsString (storage_->context , storage_->value );
431- }
406+ bool isObject () const { return isJSC () && JSValueIsObject (jscContext (), jscValue ()); }
407+ bool isString () const { return isJSC () && JSValueIsString (jscContext (), jscValue ()); }
432408 bool isBigInt () const {
433- if (storage_->kind != jscengine::ValueStorage::Kind::JSC &&
434- storage_->kind != jscengine::ValueStorage::Kind::JSCBorrowed) {
409+ if (!isJSC ()) {
435410 return false ;
436411 }
437412 if (__builtin_available (macOS 15.0 , iOS 18.0 , *)) {
438- return JSValueIsBigInt (storage_-> context , storage_-> value );
413+ return JSValueIsBigInt (jscContext (), jscValue () );
439414 }
440415 return false ;
441416 }
442- bool isSymbol () const {
443- return (storage_->kind == jscengine::ValueStorage::Kind::JSC ||
444- storage_->kind == jscengine::ValueStorage::Kind::JSCBorrowed) &&
445- JSValueIsSymbol (storage_->context , storage_->value );
446- }
417+ bool isSymbol () const { return isJSC () && JSValueIsSymbol (jscContext (), jscValue ()); }
447418
448419 Object asObject (Runtime& runtime) const ;
449420 String asString (Runtime& runtime) const ;
450421 BigInt getBigInt (Runtime& runtime) const ;
451422
452423 JSValueRef local (Runtime& runtime) const {
453- switch (storage_-> kind ) {
424+ switch (kind_ ) {
454425 case jscengine::ValueStorage::Kind::Undefined:
455426 return JSValueMakeUndefined (runtime.context ());
456427 case jscengine::ValueStorage::Kind::Null:
457428 return JSValueMakeNull (runtime.context ());
458429 case jscengine::ValueStorage::Kind::Bool:
459- return JSValueMakeBoolean (runtime.context (), storage_-> boolValue );
430+ return JSValueMakeBoolean (runtime.context (), boolValue_ );
460431 case jscengine::ValueStorage::Kind::Number:
461- return JSValueMakeNumber (runtime.context (), storage_-> numberValue );
432+ return JSValueMakeNumber (runtime.context (), numberValue_ );
462433 case jscengine::ValueStorage::Kind::JSC :
463- case jscengine::ValueStorage::Kind::JSCBorrowed:
464434 return storage_->value ;
435+ case jscengine::ValueStorage::Kind::JSCBorrowed:
436+ return borrowedValue_;
465437 }
466438 }
467439
440+ // Access the shared storage (for Object/Function/Array interop)
441+ std::shared_ptr<jscengine::ValueStorage> storage () const { return storage_; }
442+
443+ static Value fromStorage (std::shared_ptr<jscengine::ValueStorage> s) {
444+ Value v;
445+ v.kind_ = s->kind ;
446+ v.boolValue_ = s->boolValue ;
447+ v.numberValue_ = s->numberValue ;
448+ v.storage_ = std::move (s);
449+ return v;
450+ }
451+
468452 private:
469453 friend class Runtime;
470454 friend class Object;
@@ -473,6 +457,24 @@ class Value {
473457 friend class ArrayBuffer;
474458 friend class Function;
475459 friend class Array;
460+
461+ bool isJSC () const {
462+ return kind_ == jscengine::ValueStorage::Kind::JSC ||
463+ kind_ == jscengine::ValueStorage::Kind::JSCBorrowed;
464+ }
465+ JSContextRef jscContext () const {
466+ return kind_ == jscengine::ValueStorage::Kind::JSCBorrowed ? borrowedContext_
467+ : storage_->context ;
468+ }
469+ JSValueRef jscValue () const {
470+ return kind_ == jscengine::ValueStorage::Kind::JSCBorrowed ? borrowedValue_ : storage_->value ;
471+ }
472+
473+ jscengine::ValueStorage::Kind kind_ = jscengine::ValueStorage::Kind::Undefined;
474+ bool boolValue_ = false ;
475+ double numberValue_ = 0 ;
476+ JSGlobalContextRef borrowedContext_ = nullptr ;
477+ JSValueRef borrowedValue_ = nullptr ;
476478 std::shared_ptr<jscengine::ValueStorage> storage_;
477479};
478480
@@ -626,11 +628,7 @@ class Object {
626628 return reinterpret_cast<JSObjectRef>(const_cast<OpaqueJSValue*>(storage_->value ));
627629 }
628630
629- operator Value () const {
630- Value value;
631- value.storage_ = storage_;
632- return value;
633- }
631+ operator Value () const { return Value::fromStorage (storage_); }
634632
635633 protected:
636634 friend class Value;
@@ -829,11 +827,7 @@ class BigInt {
829827
830828 JSValueRef local (Runtime& runtime) const { return storage_->value ; }
831829
832- operator Value () const {
833- Value value;
834- value.storage_ = storage_;
835- return value;
836- }
830+ operator Value () const { return Value::fromStorage (storage_); }
837831
838832 private:
839833 friend class Value;
0 commit comments