Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Jint.Tests/Runtime/PropertyDescriptorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,21 @@ public void AllForbiddenDescriptor()
Assert.Equal(true, pd.IsDataDescriptor());
}

[Fact]
public void FastSetPropertyIsVisibleOnBuiltinShapedHost()
{
// Math uses builtin-shape storage; a raw property store must deopt it to dictionary
// mode — without that, the write lands in a side dictionary the shape-mode read
// paths never consult and the property silently doesn't exist.
Assert.Equal(4, _engine.Evaluate("Math.floor(4.7)").AsNumber()); // initialize the shaped host
var math = _engine.Evaluate("Math").AsObject();
math.FastSetProperty("custom", new PropertyDescriptor(42, PropertyFlag.ConfigurableEnumerableWritable));

Assert.Equal(42, _engine.Evaluate("Math.custom").AsNumber());
Assert.True(_engine.Evaluate("Object.getOwnPropertyNames(Math).includes('custom')").AsBoolean());
Assert.Equal(4, _engine.Evaluate("Math.floor(4.7)").AsNumber());
}

[Fact]
public void LazyPropertyDescriptor()
{
Expand Down
6 changes: 6 additions & 0 deletions Jint/Native/Object/ObjectInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,16 @@ internal void SetProperty(string property, PropertyDescriptor value)
internal void SetProperty(Key property, PropertyDescriptor value)
{
// Storing a raw descriptor is a dictionary-mode operation; deopt first if needed.
// Without the builtin-shape deopt, the write would land in a side dictionary that the
// shape-mode read paths never consult — the property would silently not exist.
if ((_type & InternalTypes.ShapeMode) != InternalTypes.Empty)
{
ConvertToDictionaryMode();
}
else if ((_type & InternalTypes.BuiltinShapeMode) != InternalTypes.Empty)
{
DeoptBuiltinShape();
}
_properties ??= new PropertyDictionary();
_properties[property] = value;
unchecked { _propertiesVersion++; }
Expand Down