EvalFunction.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. using Jint.Runtime;
  2. using Jint.Runtime.Descriptors;
  3. using Jint.Runtime.Environments;
  4. using Jint.Runtime.Interpreter.Statements;
  5. using Environment = Jint.Runtime.Environments.Environment;
  6. namespace Jint.Native.Function;
  7. public sealed class EvalFunction : Function
  8. {
  9. private static readonly JsString _functionName = new("eval");
  10. internal EvalFunction(
  11. Engine engine,
  12. Realm realm,
  13. FunctionPrototype functionPrototype)
  14. : base(
  15. engine,
  16. realm,
  17. _functionName,
  18. StrictModeScope.IsStrictModeCode ? FunctionThisMode.Strict : FunctionThisMode.Global)
  19. {
  20. _prototype = functionPrototype;
  21. _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
  22. }
  23. protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
  24. {
  25. var callerRealm = _engine.ExecutionContext.Realm;
  26. var x = arguments.At(0);
  27. return PerformEval(x, callerRealm, false, false);
  28. }
  29. /// <summary>
  30. /// https://tc39.es/ecma262/#sec-performeval
  31. /// </summary>
  32. internal JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bool direct)
  33. {
  34. if (!x.IsString())
  35. {
  36. return x;
  37. }
  38. var evalRealm = _realm;
  39. _engine._host.EnsureCanCompileStrings(callerRealm, evalRealm);
  40. var inFunction = false;
  41. var inMethod = false;
  42. var inDerivedConstructor = false;
  43. var inClassFieldInitializer = false;
  44. if (direct)
  45. {
  46. var thisEnvRec = _engine.ExecutionContext.GetThisEnvironment();
  47. if (thisEnvRec is FunctionEnvironment functionEnvironmentRecord)
  48. {
  49. var F = functionEnvironmentRecord._functionObject;
  50. inFunction = true;
  51. inMethod = thisEnvRec.HasSuperBinding();
  52. if (F._constructorKind == ConstructorKind.Derived)
  53. {
  54. inDerivedConstructor = true;
  55. }
  56. var classFieldInitializerName = (F as ScriptFunction)?._classFieldInitializerName;
  57. if (!string.IsNullOrEmpty(classFieldInitializerName?.ToString()))
  58. {
  59. inClassFieldInitializer = true;
  60. }
  61. }
  62. }
  63. Script? script = null;
  64. var parserOptions = _engine.GetActiveParserOptions();
  65. var adjustedParserOptions = !parserOptions.Tolerant || parserOptions.AllowReturnOutsideFunction
  66. ? parserOptions with { Tolerant = true, AllowReturnOutsideFunction = false }
  67. : parserOptions;
  68. var parser = _engine.GetParserFor(adjustedParserOptions);
  69. try
  70. {
  71. script = parser.ParseScript(x.ToString(), strict: strictCaller);
  72. }
  73. catch (ParseErrorException 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 == NodeType.Super;
  189. return base.VisitMemberExpression(memberExpression);
  190. }
  191. protected override object? VisitCallExpression(CallExpression callExpression)
  192. {
  193. _containsSuperCall |= callExpression.Callee.Type == NodeType.Super;
  194. return base.VisitCallExpression(callExpression);
  195. }
  196. }
  197. }