@@ -267,20 +267,18 @@ namespace Js
267
267
return scriptContext->GetLibrary ()->GetUndefined ();
268
268
}
269
269
270
- Var EngineInterfaceObject::Entry_TagPublicLibraryCode (RecyclableObject *function, CallInfo callInfo, ...)
270
+ /* static */
271
+ template <bool isConstructor>
272
+ ScriptFunction *EngineInterfaceObject::CreateLibraryCodeScriptFunction (ScriptFunction *scriptFunction, JavascriptString *displayName)
271
273
{
272
- EngineInterfaceObject_CommonFunctionProlog (function, callInfo);
273
-
274
- AssertOrFailFast ((callInfo.Count == 3 || callInfo.Count == 4 ) && JavascriptFunction::Is (args[1 ]) && JavascriptString::Is (args[2 ]));
275
-
276
- JavascriptFunction *func = JavascriptFunction::UnsafeFromVar (args[1 ]);
277
- JavascriptString *methodName = JavascriptString::UnsafeFromVar (args[2 ]);
278
-
279
- func->GetFunctionProxy ()->SetIsPublicLibraryCode ();
280
-
281
- // use GetSz rather than GetString because we use wcsrchr below, which expects a null-terminated string
282
- const char16 *methodNameBuf = methodName->GetSz ();
283
- charcount_t methodNameLength = methodName->GetLength ();
274
+ ScriptContext *scriptContext = scriptFunction->GetScriptContext ();
275
+ scriptFunction->GetFunctionProxy ()->SetIsPublicLibraryCode ();
276
+
277
+ // Use GetSz rather than GetString because we use wcsrchr below, which expects a null-terminated string
278
+ // Callers can pass in a string like "get compare" or "Intl.Collator.prototype.resolvedOptions" -- only for the
279
+ // latter do we extract a shortName.
280
+ const char16 *methodNameBuf = displayName->GetSz ();
281
+ charcount_t methodNameLength = displayName->GetLength ();
284
282
const char16 *shortName = wcsrchr (methodNameBuf, _u (' .' ));
285
283
charcount_t shortNameOffset = 0 ;
286
284
if (shortName != nullptr )
@@ -289,25 +287,79 @@ namespace Js
289
287
shortNameOffset = static_cast <charcount_t >(shortName - methodNameBuf);
290
288
}
291
289
292
- func->GetFunctionProxy ()->EnsureDeserialized ()->SetDisplayName (methodNameBuf, methodNameLength, shortNameOffset);
290
+ scriptFunction->GetFunctionProxy ()->EnsureDeserialized ()->SetDisplayName (methodNameBuf, methodNameLength, shortNameOffset);
291
+
292
+ if (!isConstructor)
293
+ {
294
+ // set the ErrorOnNew attribute to disallow construction. JsBuiltIn/Intl functions are usually regular ScriptFunctions
295
+ // (not lambdas or class methods), so they are usually constructable by default.
296
+ FunctionInfo *info = scriptFunction->GetFunctionInfo ();
297
+ AssertMsg ((info->GetAttributes () & FunctionInfo::Attributes::ErrorOnNew) == 0 , " Why are we trying to disable construction of a function that already isn't constructable?" );
298
+ info->SetAttributes ((FunctionInfo::Attributes) (info->GetAttributes () | FunctionInfo::Attributes::ErrorOnNew));
299
+
300
+ // Assert that the type handler is deferred to ensure that we aren't overwriting previous modifications.
301
+ // Script functions start with deferred type handlers, which undefer as soon as any property is modified.
302
+ // Since the function that is passed in should be an inline function expression, its type should still be deferred by the time it gets here.
303
+ AssertOrFailFast (scriptFunction->GetDynamicType ()->GetTypeHandler ()->IsDeferredTypeHandler ());
293
304
294
- bool creatingConstructor = true ;
295
- if (callInfo.Count == 4 )
305
+ // give the function a type handler with name and length but without prototype
306
+ DynamicTypeHandler::SetInstanceTypeHandler (scriptFunction, scriptContext->GetLibrary ()->GetDeferredFunctionWithLengthTypeHandler ());
307
+ }
308
+ else
296
309
{
297
- AssertOrFailFast (JavascriptBoolean::Is (args[3 ]));
298
- creatingConstructor = JavascriptBoolean::UnsafeFromVar (args[3 ])->GetValue ();
310
+ AssertMsg ((scriptFunction->GetFunctionInfo ()->GetAttributes () & FunctionInfo::Attributes::ErrorOnNew) == 0 , " Why is the function not constructable by default?" );
299
311
}
300
312
301
- if (!creatingConstructor)
313
+ Var existingName = nullptr ;
314
+ if (JavascriptOperators::GetOwnProperty (scriptFunction, PropertyIds::name, &existingName, scriptContext, nullptr ))
302
315
{
303
- FunctionInfo *info = func->GetFunctionInfo ();
304
- info->SetAttributes ((FunctionInfo::Attributes) (info->GetAttributes () | FunctionInfo::Attributes::ErrorOnNew));
316
+ JavascriptString *existingNameString = JavascriptString::FromVar (existingName);
317
+ if (existingNameString->GetLength () == 0 )
318
+ {
319
+ // Only overwrite the name of the function object if it was anonymous coming in
320
+ // If the input function was named, it is likely intentional
321
+ existingName = nullptr ;
322
+ }
323
+ }
305
324
306
- AssertOrFailFast (func->GetDynamicType ()->GetTypeHandler ()->IsDeferredTypeHandler ());
307
- DynamicTypeHandler::SetInstanceTypeHandler (func, scriptContext->GetLibrary ()->GetDeferredFunctionWithLengthTypeHandler ());
325
+ if (existingName == nullptr || JavascriptOperators::IsUndefined (existingName))
326
+ {
327
+ // It is convenient to set the name here rather than in script, since it is often duplicated.
328
+ JavascriptString *funcName = displayName;
329
+ if (shortName)
330
+ {
331
+ funcName = JavascriptString::NewCopyBuffer (shortName, methodNameLength - shortNameOffset, scriptContext);
332
+ }
333
+
334
+ scriptFunction->SetPropertyWithAttributes (PropertyIds::name, funcName, PropertyConfigurable, nullptr );
335
+ }
336
+
337
+ return scriptFunction;
338
+ }
339
+
340
+ Var EngineInterfaceObject::Entry_TagPublicLibraryCode (RecyclableObject *function, CallInfo callInfo, ...)
341
+ {
342
+ #pragma warning(push)
343
+ #pragma warning(disable: 4189) // 'scriptContext': local variable is initialized but not referenced
344
+ EngineInterfaceObject_CommonFunctionProlog (function, callInfo);
345
+ #pragma warning(pop)
346
+
347
+ AssertOrFailFast ((args.Info .Count == 3 || args.Info .Count == 4 ) && ScriptFunction::Is (args.Values [1 ]) && JavascriptString::Is (args.Values [2 ]));
348
+
349
+ ScriptFunction *func = ScriptFunction::UnsafeFromVar (args[1 ]);
350
+ JavascriptString *methodName = JavascriptString::UnsafeFromVar (args[2 ]);
351
+
352
+ if (args.Info .Count == 4 )
353
+ {
354
+ AssertOrFailFast (JavascriptBoolean::Is (args.Values [3 ]));
355
+ if (!JavascriptBoolean::UnsafeFromVar (args.Values [3 ])->GetValue ())
356
+ {
357
+ return CreateLibraryCodeScriptFunction<false >(func, methodName);
358
+ }
308
359
}
309
360
310
- return func;
361
+ // isConstructor = true is the default (when no 3rd arg is provided)
362
+ return CreateLibraryCodeScriptFunction<true >(func, methodName);
311
363
}
312
364
313
365
/*
0 commit comments