EvalFunction.cs 7.6 KB

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