Skip to content

Commit c1eb8c5

Browse files
rhuanjljackhorton
authored andcommitted
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 1ef7ea8 commit c1eb8c5

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
@@ -2504,12 +2504,6 @@ void __cdecl _alloca_probe_16()
25042504
return PropertyQueryFlags::Property_Found;
25052505
}
25062506
break;
2507-
case PropertyIds::length:
2508-
if (this->IsScriptFunction())
2509-
{
2510-
return PropertyQueryFlags::Property_Found;
2511-
}
2512-
break;
25132507
}
25142508
return DynamicObject::HasPropertyQuery(propertyId, info);
25152509
}
@@ -2607,12 +2601,6 @@ void __cdecl _alloca_probe_16()
26072601
return false;
26082602
}
26092603
break;
2610-
case PropertyIds::length:
2611-
if (this->IsScriptFunction() || this->IsBoundFunction())
2612-
{
2613-
return true;
2614-
}
2615-
break;
26162604
}
26172605
}
26182606
return DynamicObject::IsConfigurable(propertyId);
@@ -2631,12 +2619,6 @@ void __cdecl _alloca_probe_16()
26312619
return false;
26322620
}
26332621
break;
2634-
case PropertyIds::length:
2635-
if (this->IsScriptFunction())
2636-
{
2637-
return false;
2638-
}
2639-
break;
26402622
}
26412623
}
26422624
return DynamicObject::IsEnumerable(propertyId);
@@ -2655,12 +2637,6 @@ void __cdecl _alloca_probe_16()
26552637
return false;
26562638
}
26572639
break;
2658-
case PropertyIds::length:
2659-
if (this->IsScriptFunction())
2660-
{
2661-
return false;
2662-
}
2663-
break;
26642640
}
26652641
}
26662642
return DynamicObject::IsWritable(propertyId);
@@ -2676,18 +2652,6 @@ void __cdecl _alloca_probe_16()
26762652
return true;
26772653
}
26782654

2679-
if (index == length)
2680-
{
2681-
if (this->IsScriptFunction() || this->IsBoundFunction())
2682-
{
2683-
if (DynamicObject::GetPropertyIndex(PropertyIds::length) == Constants::NoSlot)
2684-
{
2685-
//Only for user defined functions length is a special property.
2686-
*propertyName = requestContext->GetPropertyString(PropertyIds::length);
2687-
return true;
2688-
}
2689-
}
2690-
}
26912655
return false;
26922656
}
26932657

@@ -2978,17 +2942,6 @@ void __cdecl _alloca_probe_16()
29782942
return true;
29792943
}
29802944

2981-
if (propertyId == PropertyIds::length)
2982-
{
2983-
FunctionProxy *proxy = this->GetFunctionProxy();
2984-
if (proxy)
2985-
{
2986-
*value = TaggedInt::ToVarUnchecked(proxy->EnsureDeserialized()->GetReportedInParamsCount() - 1);
2987-
*result = true;
2988-
return true;
2989-
}
2990-
}
2991-
29922945
return false;
29932946
}
29942947

@@ -3010,14 +2963,6 @@ void __cdecl _alloca_probe_16()
30102963
isReadOnly = true;
30112964
}
30122965
break;
3013-
3014-
case PropertyIds::length:
3015-
if (this->IsScriptFunction())
3016-
{
3017-
isReadOnly = true;
3018-
}
3019-
break;
3020-
30212966
}
30222967

30232968
if (isReadOnly)
@@ -3079,13 +3024,6 @@ void __cdecl _alloca_probe_16()
30793024
return false;
30803025
}
30813026
break;
3082-
case PropertyIds::length:
3083-
if (this->IsScriptFunction())
3084-
{
3085-
JavascriptError::ThrowCantDeleteIfStrictMode(flags, this->GetScriptContext(), this->GetScriptContext()->GetPropertyName(propertyId)->GetBuffer());
3086-
return false;
3087-
}
3088-
break;
30893027
}
30903028

30913029
BOOL result = DynamicObject::DeleteProperty(propertyId, flags);
@@ -3113,14 +3051,6 @@ void __cdecl _alloca_probe_16()
31133051
return false;
31143052
}
31153053
}
3116-
else if (BuiltInPropertyRecords::length.Equals(propertyNameString))
3117-
{
3118-
if (this->IsScriptFunction())
3119-
{
3120-
JavascriptError::ThrowCantDeleteIfStrictMode(flags, this->GetScriptContext(), propertyNameString->GetString());
3121-
return false;
3122-
}
3123-
}
31243054

31253055
BOOL result = DynamicObject::DeleteProperty(propertyNameString, flags);
31263056

0 commit comments

Comments
 (0)