Skip to content

Commit ab44a45

Browse files
committed
Implement function.length in typesystem
Remove all special casing of length from BoundFunction.cpp and JavascriptFunction.cpp As a result of above configurability of function.length and boundFunction.length
1 parent bb8eb71 commit ab44a45

File tree

10 files changed

+255
-260
lines changed

10 files changed

+255
-260
lines changed

lib/Runtime/Library/BoundFunction.cpp

Lines changed: 14 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,19 @@ namespace Js
4444
}
4545
type->SetPrototype(proto);
4646
}
47+
48+
int len = 0;
4749
// If targetFunction is proxy, need to make sure that traps are called in right order as per 19.2.3.2 in RC#4 dated April 3rd 2015.
48-
// Here although we won't use value of length, this is just to make sure that we call traps involved with HasOwnProperty(Target, "length") and Get(Target, "length")
49-
if (JavascriptProxy::Is(targetFunction))
50+
// additionally need to get the correct length value for the boundFunctions' length property
51+
if (JavascriptOperators::HasOwnProperty(targetFunction, PropertyIds::length, scriptContext, nullptr) == TRUE)
5052
{
51-
if (JavascriptOperators::HasOwnProperty(targetFunction, PropertyIds::length, scriptContext, nullptr) == TRUE)
53+
Var varLength;
54+
if (targetFunction->GetProperty(targetFunction, PropertyIds::length, &varLength, nullptr, scriptContext))
5255
{
53-
int len = 0;
54-
Var varLength;
55-
if (targetFunction->GetProperty(targetFunction, PropertyIds::length, &varLength, nullptr, scriptContext))
56-
{
57-
len = JavascriptConversion::ToInt32(varLength, scriptContext);
58-
}
56+
len = JavascriptConversion::ToInt32(varLength, scriptContext);
5957
}
60-
GetTypeHandler()->EnsureObjectReady(this);
6158
}
59+
GetTypeHandler()->EnsureObjectReady(this);
6260

6361
if (args.Info.Count > 1)
6462
{
@@ -84,6 +82,12 @@ namespace Js
8482
// If no "this" is passed, "undefined" is used
8583
boundThis = scriptContext->GetLibrary()->GetUndefined();
8684
}
85+
86+
// Reduce length number of bound args
87+
len = len - this->count;
88+
len = max(len, 0);
89+
90+
SetPropertyWithAttributes(PropertyIds::length, TaggedInt::ToVarUnchecked(len), PropertyConfigurable, nullptr, PropertyOperation_None, SideEffects_None);
8791
}
8892

8993
BoundFunction::BoundFunction(RecyclableObject* targetFunction, Var boundThis, Var* args, uint argsCount, DynamicType * type)
@@ -307,108 +311,11 @@ namespace Js
307311
return false;
308312
}
309313

310-
PropertyQueryFlags BoundFunction::HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info)
311-
{
312-
if (propertyId == PropertyIds::length)
313-
{
314-
return PropertyQueryFlags::Property_Found;
315-
}
316-
317-
return JavascriptFunction::HasPropertyQuery(propertyId, info);
318-
}
319-
320-
PropertyQueryFlags BoundFunction::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
321-
{
322-
BOOL result;
323-
if (GetPropertyBuiltIns(originalInstance, propertyId, value, info, requestContext, &result))
324-
{
325-
return JavascriptConversion::BooleanToPropertyQueryFlags(result);
326-
}
327-
328-
return JavascriptFunction::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
329-
}
330-
331-
PropertyQueryFlags BoundFunction::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
332-
{
333-
BOOL result;
334-
PropertyRecord const* propertyRecord;
335-
this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
336-
337-
if (propertyRecord != nullptr && GetPropertyBuiltIns(originalInstance, propertyRecord->GetPropertyId(), value, info, requestContext, &result))
338-
{
339-
return JavascriptConversion::BooleanToPropertyQueryFlags(result);
340-
}
341-
342-
return JavascriptFunction::GetPropertyQuery(originalInstance, propertyNameString, value, info, requestContext);
343-
}
344-
345-
bool BoundFunction::GetPropertyBuiltIns(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext, BOOL* result)
346-
{
347-
if (propertyId == PropertyIds::length)
348-
{
349-
// 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))
353-
{
354-
len = JavascriptConversion::ToInt32(varLength, requestContext);
355-
}
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;
364-
}
365-
366-
return false;
367-
}
368-
369314
PropertyQueryFlags BoundFunction::GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
370315
{
371316
return BoundFunction::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
372317
}
373318

374-
BOOL BoundFunction::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
375-
{
376-
BOOL result;
377-
if (SetPropertyBuiltIns(propertyId, value, flags, info, &result))
378-
{
379-
return result;
380-
}
381-
382-
return JavascriptFunction::SetProperty(propertyId, value, flags, info);
383-
}
384-
385-
BOOL BoundFunction::SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
386-
{
387-
BOOL result;
388-
PropertyRecord const* propertyRecord;
389-
this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
390-
391-
if (propertyRecord != nullptr && SetPropertyBuiltIns(propertyRecord->GetPropertyId(), value, flags, info, &result))
392-
{
393-
return result;
394-
}
395-
396-
return JavascriptFunction::SetProperty(propertyNameString, value, flags, info);
397-
}
398-
399-
bool BoundFunction::SetPropertyBuiltIns(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info, BOOL* result)
400-
{
401-
if (propertyId == PropertyIds::length)
402-
{
403-
JavascriptError::ThrowCantAssignIfStrictMode(flags, this->GetScriptContext());
404-
405-
*result = false;
406-
return true;
407-
}
408-
409-
return false;
410-
}
411-
412319
_Check_return_ _Success_(return) BOOL BoundFunction::GetAccessors(PropertyId propertyId, _Outptr_result_maybenull_ Var* getter, _Outptr_result_maybenull_ Var* setter, ScriptContext* requestContext)
413320
{
414321
return DynamicObject::GetAccessors(propertyId, getter, setter, requestContext);
@@ -429,56 +336,6 @@ namespace Js
429336
return SetProperty(propertyId, value, PropertyOperation_None, info);
430337
}
431338

432-
BOOL BoundFunction::DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags)
433-
{
434-
if (propertyId == PropertyIds::length)
435-
{
436-
return false;
437-
}
438-
439-
return JavascriptFunction::DeleteProperty(propertyId, flags);
440-
}
441-
442-
BOOL BoundFunction::DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags)
443-
{
444-
if (BuiltInPropertyRecords::length.Equals(propertyNameString))
445-
{
446-
return false;
447-
}
448-
449-
return JavascriptFunction::DeleteProperty(propertyNameString, flags);
450-
}
451-
452-
BOOL BoundFunction::IsWritable(PropertyId propertyId)
453-
{
454-
if (propertyId == PropertyIds::length)
455-
{
456-
return false;
457-
}
458-
459-
return JavascriptFunction::IsWritable(propertyId);
460-
}
461-
462-
BOOL BoundFunction::IsConfigurable(PropertyId propertyId)
463-
{
464-
if (propertyId == PropertyIds::length)
465-
{
466-
return false;
467-
}
468-
469-
return JavascriptFunction::IsConfigurable(propertyId);
470-
}
471-
472-
BOOL BoundFunction::IsEnumerable(PropertyId propertyId)
473-
{
474-
if (propertyId == PropertyIds::length)
475-
{
476-
return false;
477-
}
478-
479-
return JavascriptFunction::IsEnumerable(propertyId);
480-
}
481-
482339
BOOL BoundFunction::HasInstance(Var instance, ScriptContext* scriptContext, IsInstInlineCache* inlineCache)
483340
{
484341
return this->targetFunction->HasInstance(instance, scriptContext, inlineCache);

lib/Runtime/Library/BoundFunction.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,13 @@ namespace Js
2626
static bool Is(Var func){ return JavascriptFunction::Is(func) && JavascriptFunction::UnsafeFromVar(func)->IsBoundFunction(); }
2727
static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
2828
virtual JavascriptString* GetDisplayNameImpl() const override;
29-
virtual PropertyQueryFlags HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info) override;
30-
virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
31-
virtual PropertyQueryFlags GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
3229
virtual PropertyQueryFlags GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
33-
virtual BOOL SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
34-
virtual BOOL SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) override;
3530

3631
_Check_return_ _Success_(return) virtual BOOL GetAccessors(PropertyId propertyId, _Outptr_result_maybenull_ Var* getter, _Outptr_result_maybenull_ Var* setter, ScriptContext* requestContext) override;
3732
virtual DescriptorFlags GetSetter(PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override;
3833
virtual DescriptorFlags GetSetter(JavascriptString* propertyNameString, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext) override;
3934

4035
virtual BOOL InitProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags = PropertyOperation_None, PropertyValueInfo* info = NULL) override;
41-
virtual BOOL DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags) override;
42-
virtual BOOL DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags) override;
43-
44-
virtual BOOL IsWritable(PropertyId propertyId) override;
45-
virtual BOOL IsConfigurable(PropertyId propertyId) override;
46-
virtual BOOL IsEnumerable(PropertyId propertyId) override;
4736
virtual BOOL HasInstance(Var instance, ScriptContext* scriptContext, IsInstInlineCache* inlineCache = NULL) override;
4837
virtual inline BOOL IsConstructor() const override;
4938

lib/Runtime/Library/JavascriptExternalFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ namespace Js
5858

5959
bool __cdecl JavascriptExternalFunction::DeferredLengthInitializer(DynamicObject * instance, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
6060
{
61-
Js::JavascriptLibrary::InitializeFunction<true>(instance, typeHandler, mode);
61+
Js::JavascriptLibrary::InitializeFunction<true, true, true>(instance, typeHandler, mode);
6262

6363
JavascriptExternalFunction* object = static_cast<JavascriptExternalFunction*>(instance);
6464

lib/Runtime/Library/JavascriptFunction.cpp

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2496,12 +2496,6 @@ void __cdecl _alloca_probe_16()
24962496
return PropertyQueryFlags::Property_Found;
24972497
}
24982498
break;
2499-
case PropertyIds::length:
2500-
if (this->IsScriptFunction())
2501-
{
2502-
return PropertyQueryFlags::Property_Found;
2503-
}
2504-
break;
25052499
}
25062500
return DynamicObject::HasPropertyQuery(propertyId, info);
25072501
}
@@ -2599,12 +2593,6 @@ void __cdecl _alloca_probe_16()
25992593
return false;
26002594
}
26012595
break;
2602-
case PropertyIds::length:
2603-
if (this->IsScriptFunction() || this->IsBoundFunction())
2604-
{
2605-
return true;
2606-
}
2607-
break;
26082596
}
26092597
}
26102598
return DynamicObject::IsConfigurable(propertyId);
@@ -2623,12 +2611,6 @@ void __cdecl _alloca_probe_16()
26232611
return false;
26242612
}
26252613
break;
2626-
case PropertyIds::length:
2627-
if (this->IsScriptFunction())
2628-
{
2629-
return false;
2630-
}
2631-
break;
26322614
}
26332615
}
26342616
return DynamicObject::IsEnumerable(propertyId);
@@ -2647,12 +2629,6 @@ void __cdecl _alloca_probe_16()
26472629
return false;
26482630
}
26492631
break;
2650-
case PropertyIds::length:
2651-
if (this->IsScriptFunction())
2652-
{
2653-
return false;
2654-
}
2655-
break;
26562632
}
26572633
}
26582634
return DynamicObject::IsWritable(propertyId);
@@ -2668,18 +2644,6 @@ void __cdecl _alloca_probe_16()
26682644
return true;
26692645
}
26702646

2671-
if (index == length)
2672-
{
2673-
if (this->IsScriptFunction() || this->IsBoundFunction())
2674-
{
2675-
if (DynamicObject::GetPropertyIndex(PropertyIds::length) == Constants::NoSlot)
2676-
{
2677-
//Only for user defined functions length is a special property.
2678-
*propertyName = requestContext->GetPropertyString(PropertyIds::length);
2679-
return true;
2680-
}
2681-
}
2682-
}
26832647
return false;
26842648
}
26852649

@@ -2970,17 +2934,6 @@ void __cdecl _alloca_probe_16()
29702934
return true;
29712935
}
29722936

2973-
if (propertyId == PropertyIds::length)
2974-
{
2975-
FunctionProxy *proxy = this->GetFunctionProxy();
2976-
if (proxy)
2977-
{
2978-
*value = TaggedInt::ToVarUnchecked(proxy->EnsureDeserialized()->GetReportedInParamsCount() - 1);
2979-
*result = true;
2980-
return true;
2981-
}
2982-
}
2983-
29842937
return false;
29852938
}
29862939

@@ -3002,14 +2955,6 @@ void __cdecl _alloca_probe_16()
30022955
isReadOnly = true;
30032956
}
30042957
break;
3005-
3006-
case PropertyIds::length:
3007-
if (this->IsScriptFunction())
3008-
{
3009-
isReadOnly = true;
3010-
}
3011-
break;
3012-
30132958
}
30142959

30152960
if (isReadOnly)
@@ -3071,13 +3016,6 @@ void __cdecl _alloca_probe_16()
30713016
return false;
30723017
}
30733018
break;
3074-
case PropertyIds::length:
3075-
if (this->IsScriptFunction())
3076-
{
3077-
JavascriptError::ThrowCantDeleteIfStrictMode(flags, this->GetScriptContext(), this->GetScriptContext()->GetPropertyName(propertyId)->GetBuffer());
3078-
return false;
3079-
}
3080-
break;
30813019
}
30823020

30833021
BOOL result = DynamicObject::DeleteProperty(propertyId, flags);
@@ -3105,14 +3043,6 @@ void __cdecl _alloca_probe_16()
31053043
return false;
31063044
}
31073045
}
3108-
else if (BuiltInPropertyRecords::length.Equals(propertyNameString))
3109-
{
3110-
if (this->IsScriptFunction())
3111-
{
3112-
JavascriptError::ThrowCantDeleteIfStrictMode(flags, this->GetScriptContext(), propertyNameString->GetString());
3113-
return false;
3114-
}
3115-
}
31163046

31173047
BOOL result = DynamicObject::DeleteProperty(propertyNameString, flags);
31183048

0 commit comments

Comments
 (0)