Skip to content

Commit 3d2b284

Browse files
committed
Fix function.length and boundFunction.length
1 parent 5ec0ca7 commit 3d2b284

File tree

7 files changed

+220
-108
lines changed

7 files changed

+220
-108
lines changed

lib/Runtime/Library/BoundFunction.cpp

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -309,17 +309,15 @@ namespace Js
309309

310310
PropertyQueryFlags BoundFunction::HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info)
311311
{
312-
if (propertyId == PropertyIds::length)
313-
{
314-
return PropertyQueryFlags::Property_Found;
315-
}
312+
EnsureLength();
316313

317314
return JavascriptFunction::HasPropertyQuery(propertyId, info);
318315
}
319316

320317
PropertyQueryFlags BoundFunction::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
321318
{
322319
BOOL result;
320+
EnsureLength();
323321
if (GetPropertyBuiltIns(originalInstance, propertyId, value, info, requestContext, &result))
324322
{
325323
return JavascriptConversion::BooleanToPropertyQueryFlags(result);
@@ -332,6 +330,7 @@ namespace Js
332330
{
333331
BOOL result;
334332
PropertyRecord const* propertyRecord;
333+
EnsureLength();
335334
this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
336335

337336
if (propertyRecord != nullptr && GetPropertyBuiltIns(originalInstance, propertyRecord->GetPropertyId(), value, info, requestContext, &result))
@@ -344,23 +343,13 @@ namespace Js
344343

345344
bool BoundFunction::GetPropertyBuiltIns(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext, BOOL* result)
346345
{
347-
if (propertyId == PropertyIds::length)
346+
if (!EnsureLength() && propertyId == PropertyIds::length)
348347
{
349348
// Get the "length" property of the underlying target function
350-
int len = 0;
351-
Var varLength;
352-
if (targetFunction->GetProperty(targetFunction, PropertyIds::length, &varLength, nullptr, requestContext))
349+
if (GetPropertyQuery(originalInstance, propertyId, value, info, requestContext) == PropertyQueryFlags::Property_Found)
353350
{
354-
len = JavascriptConversion::ToInt32(varLength, requestContext);
351+
return true;
355352
}
356-
357-
// Reduce by number of bound args
358-
len = len - this->count;
359-
len = max(len, 0);
360-
361-
*value = JavascriptNumber::ToVar(len, requestContext);
362-
*result = true;
363-
return true;
364353
}
365354

366355
return false;
@@ -374,6 +363,7 @@ namespace Js
374363
BOOL BoundFunction::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
375364
{
376365
BOOL result;
366+
EnsureLength();
377367
if (SetPropertyBuiltIns(propertyId, value, flags, info, &result))
378368
{
379369
return result;
@@ -386,6 +376,7 @@ namespace Js
386376
{
387377
BOOL result;
388378
PropertyRecord const* propertyRecord;
379+
EnsureLength();
389380
this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
390381

391382
if (propertyRecord != nullptr && SetPropertyBuiltIns(propertyRecord->GetPropertyId(), value, flags, info, &result))
@@ -398,13 +389,7 @@ namespace Js
398389

399390
bool BoundFunction::SetPropertyBuiltIns(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info, BOOL* result)
400391
{
401-
if (propertyId == PropertyIds::length)
402-
{
403-
JavascriptError::ThrowCantAssignIfStrictMode(flags, this->GetScriptContext());
404-
405-
*result = false;
406-
return true;
407-
}
392+
EnsureLength();
408393

409394
return false;
410395
}
@@ -431,52 +416,64 @@ namespace Js
431416

432417
BOOL BoundFunction::DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags)
433418
{
434-
if (propertyId == PropertyIds::length)
435-
{
436-
return false;
437-
}
419+
EnsureLength();
438420

439421
return JavascriptFunction::DeleteProperty(propertyId, flags);
440422
}
441423

442424
BOOL BoundFunction::DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags)
443425
{
444-
if (BuiltInPropertyRecords::length.Equals(propertyNameString))
445-
{
446-
return false;
447-
}
426+
EnsureLength();
448427

449428
return JavascriptFunction::DeleteProperty(propertyNameString, flags);
450429
}
451430

452431
BOOL BoundFunction::IsWritable(PropertyId propertyId)
453432
{
454-
if (propertyId == PropertyIds::length)
455-
{
456-
return false;
457-
}
433+
EnsureLength();
458434

459435
return JavascriptFunction::IsWritable(propertyId);
460436
}
461437

462438
BOOL BoundFunction::IsConfigurable(PropertyId propertyId)
463439
{
464-
if (propertyId == PropertyIds::length)
465-
{
466-
return false;
467-
}
440+
EnsureLength();
468441

469442
return JavascriptFunction::IsConfigurable(propertyId);
470443
}
471444

472445
BOOL BoundFunction::IsEnumerable(PropertyId propertyId)
473446
{
474-
if (propertyId == PropertyIds::length)
447+
EnsureLength();
448+
449+
return JavascriptFunction::IsEnumerable(propertyId);
450+
}
451+
452+
bool BoundFunction::EnsureLength()
453+
{
454+
if (!lengthSet)
475455
{
456+
// Get the "length" property of the underlying target function
457+
int len = 0;
458+
if (JavascriptFunction::Is(targetFunction))
459+
{
460+
JavascriptFunction* func = JavascriptFunction::UnsafeFromVar(targetFunction);
461+
FunctionProxy* proxy = func->GetFunctionProxy();
462+
if (proxy)
463+
{
464+
len = proxy->EnsureDeserialized()->GetReportedInParamsCount() - 1;
465+
}
466+
}
467+
468+
// Reduce by number of bound args
469+
len = len - this->count;
470+
len = max(len, 0);
471+
472+
SetPropertyWithAttributes(PropertyIds::length, TaggedInt::ToVarUnchecked(len), PropertyConfigurable, nullptr, PropertyOperation_None, SideEffects_None);
473+
lengthSet = true;
476474
return false;
477475
}
478-
479-
return JavascriptFunction::IsEnumerable(propertyId);
476+
return true;
480477
}
481478

482479
BOOL BoundFunction::HasInstance(Var instance, ScriptContext* scriptContext, IsInstInlineCache* inlineCache)

lib/Runtime/Library/BoundFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace Js
2525

2626
static bool Is(Var func){ return JavascriptFunction::Is(func) && JavascriptFunction::UnsafeFromVar(func)->IsBoundFunction(); }
2727
static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
28+
bool EnsureLength();
2829
virtual JavascriptString* GetDisplayNameImpl() const override;
2930
virtual PropertyQueryFlags HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info) override;
3031
virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
@@ -73,5 +74,6 @@ namespace Js
7374
Field(Var) boundThis;
7475
Field(uint) count;
7576
Field(Field(Var)*) boundArgs;
77+
Field(bool) lengthSet = false;
7678
};
7779
} // namespace Js

0 commit comments

Comments
 (0)