EvalFunctionInstance.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using Esprima;
  2. using Esprima.Ast;
  3. using Esprima.Utils;
  4. using Jint.Runtime;
  5. using Jint.Runtime.Descriptors;
  6. using Jint.Runtime.Environments;
  7. using Jint.Runtime.Interpreter.Statements;
  8. using Environment = Jint.Runtime.Environments.Environment;
  9. namespace Jint.Native.Function;
  10. internal sealed class EvalFunctionInstance : FunctionInstance
  11. {
  12. private static readonly JsString _functionName = new("eval");
  13. private static readonly ParserOptions _parserOptions = ParserOptions.Default with { Tolerant = true };
  14. private readonly JavaScriptParser _parser = new(_parserOptions);
  15. public EvalFunctionInstance(
  16. Engine engine,
  17. Realm realm,
  18. FunctionPrototype functionPrototype)
  19. : base(
  20. engine,
  21. realm,
  22. _functionName,
  23. StrictModeScope.IsStrictModeCode ? FunctionThisMode.Strict : FunctionThisMode.Global)
  24. {
  25. _prototype = functionPrototype;
  26. _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
  27. }
  28. protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
  29. {
  30. var callerRealm = _engine.ExecutionContext.Realm;
  31. var x = arguments.At(0);
  32. return PerformEval(x, callerRealm, false, false);
  33. }
  34. /// <summary>
  35. /// https://tc39.es/ecma262/#sec-performeval
  36. /// </summary>
  37. public JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bool direct)
  38. {
  39. if (!x.IsString())
  40. {
  41. return x;
  42. }
  43. var evalRealm = _realm;
  44. _engine._host.EnsureCanCompileStrings(callerRealm, evalRealm);
  45. var inFunction = false;
  46. var inMethod = false;
  47. var inDerivedConstructor = false;
  48. var inClassFieldInitializer = false;
  49. if (direct)
  50. {
  51. var thisEnvRec = _engine.ExecutionContext.GetThisEnvironment();
  52. if (thisEnvRec is FunctionEnvironment functionEnvironmentRecord)
  53. {
  54. var F = functionEnvironmentRecord._functionObject;
  55. inFunction = true;
  56. inMethod = thisEnvRec.HasSuperBinding();
  57. if (F._constructorKind == ConstructorKind.Derived)
  58. {
  59. inDerivedConstructor = true;
  60. }
  61. var classFieldInitializerName = (F as ScriptFunctionInstance)?._classFieldInitializerName;
  62. if (!string.IsNullOrEmpty(classFieldInitializerName?.ToString()))
  63. {
  64. inClassFieldInitializer = true;
  65. }
  66. }
  67. }
  68. Script? script = null;
  69. try
  70. {
  71. script = _parser.ParseScript(x.ToString(), strict: strictCaller);
  72. }
  73. catch (ParserException e)
  74. {
  75. if (string.Equals(e.Description, Messages.InvalidLHSInAssignment, StringComparison.Ordinal))
  76. {
  77. ExceptionHelper.ThrowReferenceError(callerRealm, (string?) null);
  78. }
  79. else
  80. {
  81. ExceptionHelper.ThrowSyntaxError(callerRealm, e.Message);
  82. }
  83. }
  84. var body = script.Body;
  85. if (body.Count == 0)
  86. {
  87. return Undefined;
  88. }
  89. var analyzer = new EvalScriptAnalyzer();
  90. analyzer.Visit(script);
  91. if (!inFunction)
  92. {
  93. // if body Contains NewTarget, throw a SyntaxError exception.
  94. if (analyzer._containsNewTarget)
  95. {
  96. ExceptionHelper.ThrowSyntaxError(evalRealm, "new.target expression is not allowed here");
  97. }
  98. }
  99. if (!inMethod)
  100. {
  101. // if body Contains SuperProperty, throw a SyntaxError exception.
  102. if (analyzer._containsSuperProperty)
  103. {
  104. ExceptionHelper.ThrowSyntaxError(evalRealm, "'super' keyword unexpected here");
  105. }
  106. }
  107. if (!inDerivedConstructor)
  108. {
  109. // if body Contains SuperCall, throw a SyntaxError exception.
  110. if (analyzer._containsSuperCall)
  111. {
  112. ExceptionHelper.ThrowSyntaxError(evalRealm, "'super' keyword unexpected here");
  113. }
  114. }
  115. if (inClassFieldInitializer)
  116. {
  117. // if ContainsArguments of body is true, throw a SyntaxError exception.
  118. if (analyzer._containsArguments)
  119. {
  120. ExceptionHelper.ThrowSyntaxError(evalRealm, "'arguments' is not allowed in class field initializer or static initialization block");
  121. }
  122. }
  123. var strictEval = script.Strict || _engine._isStrict;
  124. var ctx = _engine.ExecutionContext;
  125. using (new StrictModeScope(strictEval))
  126. {
  127. Environment lexEnv;
  128. Environment varEnv;
  129. PrivateEnvironment? privateEnv;
  130. if (direct)
  131. {
  132. lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, ctx.LexicalEnvironment);
  133. varEnv = ctx.VariableEnvironment;
  134. privateEnv = ctx.PrivateEnvironment;
  135. }
  136. else
  137. {
  138. lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, evalRealm.GlobalEnv);
  139. varEnv = evalRealm.GlobalEnv;
  140. privateEnv = null;
  141. }
  142. if (strictEval)
  143. {
  144. varEnv = lexEnv;
  145. }
  146. // If ctx is not already suspended, suspend ctx.
  147. Engine.EnterExecutionContext(lexEnv, varEnv, evalRealm, privateEnv);
  148. try
  149. {
  150. Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, privateEnv, strictEval);
  151. var statement = new JintScript(script);
  152. var result = statement.Execute(_engine._activeEvaluationContext!);
  153. var value = result.GetValueOrDefault();
  154. if (result.Type == CompletionType.Throw)
  155. {
  156. ExceptionHelper.ThrowJavaScriptException(_engine, value, result);
  157. return null!;
  158. }
  159. else
  160. {
  161. return value;
  162. }
  163. }
  164. finally
  165. {
  166. Engine.LeaveExecutionContext();
  167. }
  168. }
  169. }
  170. private sealed class EvalScriptAnalyzer : AstVisitor
  171. {
  172. public bool _containsArguments;
  173. public bool _containsNewTarget;
  174. public bool _containsSuperCall;
  175. public bool _containsSuperProperty;
  176. protected override object VisitIdentifier(Identifier identifier)
  177. {
  178. _containsArguments |= string.Equals(identifier.Name, "arguments", StringComparison.Ordinal);
  179. return identifier;
  180. }
  181. protected override object VisitMetaProperty(MetaProperty metaProperty)
  182. {
  183. _containsNewTarget |= string.Equals(metaProperty.Meta.Name, "new", StringComparison.Ordinal) && string.Equals(metaProperty.Property.Name, "target", StringComparison.Ordinal);
  184. return metaProperty;
  185. }
  186. protected override object? VisitMemberExpression(MemberExpression memberExpression)
  187. {
  188. _containsSuperProperty |= memberExpression.Object.Type == Nodes.Super;
  189. return base.VisitMemberExpression(memberExpression);
  190. }
  191. protected override object? VisitCallExpression(CallExpression callExpression)
  192. {
  193. _containsSuperCall |= callExpression.Callee.Type == Nodes.Super;
  194. return base.VisitCallExpression(callExpression);
  195. }
  196. }
  197. }