ScriptFunctionInstance.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using System.Runtime.CompilerServices;
  2. using Esprima.Ast;
  3. using Jint.Native.Object;
  4. using Jint.Runtime;
  5. using Jint.Runtime.Descriptors;
  6. using Jint.Runtime.Descriptors.Specialized;
  7. using Jint.Runtime.Environments;
  8. namespace Jint.Native.Function
  9. {
  10. /// <summary>
  11. ///
  12. /// </summary>
  13. public sealed class ScriptFunctionInstance : FunctionInstance, IConstructor
  14. {
  15. private readonly IFunction _functionDeclaration;
  16. /// <summary>
  17. /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
  18. /// </summary>
  19. /// <param name="engine"></param>
  20. /// <param name="functionDeclaration"></param>
  21. /// <param name="scope"></param>
  22. /// <param name="strict"></param>
  23. public ScriptFunctionInstance(Engine engine, IFunction functionDeclaration, LexicalEnvironment scope, bool strict)
  24. : base(engine, GetParameterNames(functionDeclaration), scope, strict)
  25. {
  26. _functionDeclaration = functionDeclaration;
  27. Engine = engine;
  28. Extensible = true;
  29. Prototype = engine.Function.PrototypeObject;
  30. DefineOwnProperty("length", new AllForbiddenPropertyDescriptor(JsValue.FromInt(FormalParameters.Length)), false);
  31. var proto = engine.Object.Construct(Arguments.Empty);
  32. proto.SetOwnProperty("constructor", new NonEnumerablePropertyDescriptor(this));
  33. SetOwnProperty("prototype", new WritablePropertyDescriptor(proto));
  34. if (_functionDeclaration.Id != null)
  35. {
  36. DefineOwnProperty("name", new NullConfigurationPropertyDescriptor(_functionDeclaration.Id.Name), false);
  37. }
  38. if (strict)
  39. {
  40. var thrower = engine.Function.ThrowTypeError;
  41. DefineOwnProperty("caller", new PropertyDescriptor(thrower, thrower, false, false), false);
  42. DefineOwnProperty("arguments", new PropertyDescriptor(thrower, thrower, false, false), false);
  43. }
  44. }
  45. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  46. private static string[] GetParameterNames(IFunction functionDeclaration)
  47. {
  48. var list = functionDeclaration.Params;
  49. var count = list.Count;
  50. if (count == 0)
  51. {
  52. return System.Array.Empty<string>();
  53. }
  54. var names = new string[count];
  55. for (var i = 0; i < count; ++i)
  56. {
  57. names[i] = ((Identifier) list[i]).Name;
  58. }
  59. return names;
  60. }
  61. /// <summary>
  62. /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.1
  63. /// </summary>
  64. /// <param name="thisArg"></param>
  65. /// <param name="arguments"></param>
  66. /// <returns></returns>
  67. public override JsValue Call(JsValue thisArg, JsValue[] arguments)
  68. {
  69. using (new StrictModeScope(Strict, true))
  70. {
  71. // setup new execution context http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.3
  72. JsValue thisBinding;
  73. if (StrictModeScope.IsStrictModeCode)
  74. {
  75. thisBinding = thisArg;
  76. }
  77. else if (thisArg == Undefined.Instance || thisArg == Null.Instance)
  78. {
  79. thisBinding = Engine.Global;
  80. }
  81. else if (!thisArg.IsObject())
  82. {
  83. thisBinding = TypeConverter.ToObject(Engine, thisArg);
  84. }
  85. else
  86. {
  87. thisBinding = thisArg;
  88. }
  89. var localEnv = LexicalEnvironment.NewDeclarativeEnvironment(Engine, Scope);
  90. Engine.EnterExecutionContext(localEnv, localEnv, thisBinding);
  91. try
  92. {
  93. Engine.DeclarationBindingInstantiation(
  94. DeclarationBindingType.FunctionCode,
  95. _functionDeclaration.HoistingScope.FunctionDeclarations,
  96. _functionDeclaration.HoistingScope.VariableDeclarations,
  97. this,
  98. arguments);
  99. var result = Engine.ExecuteStatement(_functionDeclaration.Body);
  100. if (result.Type == Completion.Throw)
  101. {
  102. JavaScriptException ex = new JavaScriptException(result.GetValueOrDefault())
  103. .SetCallstack(Engine, result.Location);
  104. throw ex;
  105. }
  106. if (result.Type == Completion.Return)
  107. {
  108. return result.GetValueOrDefault();
  109. }
  110. }
  111. finally
  112. {
  113. Engine.LeaveExecutionContext();
  114. }
  115. return Undefined.Instance;
  116. }
  117. }
  118. /// <summary>
  119. /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.2
  120. /// </summary>
  121. /// <param name="arguments"></param>
  122. /// <returns></returns>
  123. public ObjectInstance Construct(JsValue[] arguments)
  124. {
  125. var proto = Get("prototype").TryCast<ObjectInstance>();
  126. var obj = new ObjectInstance(Engine);
  127. obj.Extensible = true;
  128. obj.Prototype = proto ?? Engine.Object.PrototypeObject;
  129. var result = Call(obj, arguments).TryCast<ObjectInstance>();
  130. if (result != null)
  131. {
  132. return result;
  133. }
  134. return obj;
  135. }
  136. public ObjectInstance PrototypeObject { get; private set; }
  137. }
  138. }