@@ -47,6 +47,101 @@ void emplace(size_t index, Value&& value) {
4747 alignas (Value) unsigned char inlineStorage_[sizeof (Value) * InlineCount];
4848};
4949
50+ bool findPrototypeDescriptor (Runtime& runtime, v8::Local<v8::Object> object,
51+ v8::Local<v8::Name> property,
52+ v8::Local<v8::Object>* descriptorOut) {
53+ v8::TryCatch tryCatch (runtime.isolate ());
54+ v8::Local<v8::Value> currentValue = object->GetPrototypeV2 ();
55+ for (size_t depth = 0 ; depth < 64 && currentValue->IsObject (); depth++) {
56+ v8::Local<v8::Object> current = currentValue.As <v8::Object>();
57+ v8::Local<v8::Value> descriptorValue;
58+ if (!current->GetOwnPropertyDescriptor (runtime.context (), property)
59+ .ToLocal (&descriptorValue)) {
60+ throw JSError (runtime,
61+ currentExceptionMessage (runtime.isolate (), tryCatch));
62+ }
63+ if (descriptorValue->IsObject ()) {
64+ *descriptorOut = descriptorValue.As <v8::Object>();
65+ return true ;
66+ }
67+ currentValue = current->GetPrototypeV2 ();
68+ }
69+ return false ;
70+ }
71+
72+ bool tryResolvePrototypeGet (Runtime& runtime, v8::Local<v8::Object> object,
73+ v8::Local<v8::Object> receiver,
74+ v8::Local<v8::Name> property,
75+ v8::Local<v8::Value>* resultOut) {
76+ v8::Local<v8::Object> descriptor;
77+ if (!findPrototypeDescriptor (runtime, object, property, &descriptor)) {
78+ return false ;
79+ }
80+
81+ v8::TryCatch tryCatch (runtime.isolate ());
82+ v8::Local<v8::String> getKey = makeV8String (runtime.isolate (), " get" );
83+ v8::Local<v8::Value> getterValue;
84+ if (!descriptor->Get (runtime.context (), getKey).ToLocal (&getterValue)) {
85+ throw JSError (runtime, currentExceptionMessage (runtime.isolate (), tryCatch));
86+ }
87+ if (getterValue->IsFunction ()) {
88+ v8::Local<v8::Value> result;
89+ if (!getterValue.As <v8::Function>()
90+ ->Call (runtime.context (), receiver, 0 , nullptr )
91+ .ToLocal (&result)) {
92+ throw JSError (runtime,
93+ currentExceptionMessage (runtime.isolate (), tryCatch));
94+ }
95+ *resultOut = result;
96+ return true ;
97+ }
98+
99+ v8::Local<v8::String> valueKey = makeV8String (runtime.isolate (), " value" );
100+ bool hasValue =
101+ descriptor->HasOwnProperty (runtime.context (), valueKey).FromMaybe (false );
102+ if (hasValue) {
103+ v8::Local<v8::Value> value;
104+ if (!descriptor->Get (runtime.context (), valueKey).ToLocal (&value)) {
105+ throw JSError (runtime,
106+ currentExceptionMessage (runtime.isolate (), tryCatch));
107+ }
108+ *resultOut = value;
109+ return true ;
110+ }
111+
112+ *resultOut = v8::Undefined (runtime.isolate ());
113+ return true ;
114+ }
115+
116+ bool tryInvokePrototypeSetter (Runtime& runtime, v8::Local<v8::Object> object,
117+ v8::Local<v8::Object> receiver,
118+ v8::Local<v8::Name> property,
119+ v8::Local<v8::Value> value) {
120+ v8::Local<v8::Object> descriptor;
121+ if (!findPrototypeDescriptor (runtime, object, property, &descriptor)) {
122+ return false ;
123+ }
124+
125+ v8::TryCatch tryCatch (runtime.isolate ());
126+ v8::Local<v8::String> setKey = makeV8String (runtime.isolate (), " set" );
127+ v8::Local<v8::Value> setterValue;
128+ if (!descriptor->Get (runtime.context (), setKey).ToLocal (&setterValue)) {
129+ throw JSError (runtime, currentExceptionMessage (runtime.isolate (), tryCatch));
130+ }
131+ if (!setterValue->IsFunction ()) {
132+ return false ;
133+ }
134+
135+ v8::Local<v8::Value> args[] = {value};
136+ v8::Local<v8::Value> ignored;
137+ if (!setterValue.As <v8::Function>()
138+ ->Call (runtime.context (), receiver, 1 , args)
139+ .ToLocal (&ignored)) {
140+ throw JSError (runtime, currentExceptionMessage (runtime.isolate (), tryCatch));
141+ }
142+ return true ;
143+ }
144+
50145v8::Local<v8::ObjectTemplate> hostObjectTemplate (Runtime& runtime) {
51146 auto state = runtime.state ();
52147 if (state->hostObjectTemplate .IsEmpty ()) {
@@ -251,6 +346,15 @@ void emplace(size_t index, Value&& value) {
251346 if (*utf8 == nullptr ) {
252347 return v8::Intercepted::kNo ;
253348 }
349+ v8::Local<v8::Object> holderObject = info.Holder ();
350+ v8::Local<v8::Object> receiver =
351+ info.This ()->IsObject () ? info.This ().As <v8::Object>() : holderObject;
352+ v8::Local<v8::Value> prototypeResult;
353+ if (tryResolvePrototypeGet (runtime, holderObject, receiver,
354+ property, &prototypeResult)) {
355+ info.GetReturnValue ().Set (prototypeResult);
356+ return v8::Intercepted::kYes ;
357+ }
254358 Value result = holder->hostObject ->get (
255359 runtime, PropNameID (std::string (*utf8, utf8.length ())));
256360 if (!result.isUndefined ()) {
@@ -280,6 +384,13 @@ void emplace(size_t index, Value&& value) {
280384 if (*utf8 == nullptr ) {
281385 return v8::Intercepted::kNo ;
282386 }
387+ v8::Local<v8::Object> holderObject = info.Holder ();
388+ v8::Local<v8::Object> receiver =
389+ info.This ()->IsObject () ? info.This ().As <v8::Object>() : holderObject;
390+ if (tryInvokePrototypeSetter (runtime, holderObject, receiver,
391+ property, value)) {
392+ return v8::Intercepted::kYes ;
393+ }
283394 bool handled = holder->hostObject ->set (
284395 runtime, PropNameID (std::string (*utf8, utf8.length ())),
285396 Value (runtime, value));
0 commit comments