JintIdentifierExpression.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. using System.Diagnostics.CodeAnalysis;
  2. using System.Runtime.CompilerServices;
  3. using Esprima.Ast;
  4. using Jint.Native;
  5. using Jint.Runtime.Environments;
  6. using Environment = Jint.Runtime.Environments.Environment;
  7. namespace Jint.Runtime.Interpreter.Expressions;
  8. internal sealed class JintIdentifierExpression : JintExpression
  9. {
  10. private Environment.BindingName _identifier = null!;
  11. private bool _initialized;
  12. public JintIdentifierExpression(Identifier expression) : base(expression)
  13. {
  14. }
  15. public Environment.BindingName Identifier
  16. {
  17. get
  18. {
  19. EnsureIdentifier();
  20. return _identifier;
  21. }
  22. }
  23. private void Initialize()
  24. {
  25. EnsureIdentifier();
  26. }
  27. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  28. private void EnsureIdentifier()
  29. {
  30. _identifier ??= _expression.AssociatedData as Environment.BindingName ?? new Environment.BindingName(((Identifier) _expression).Name);
  31. }
  32. public bool HasEvalOrArguments
  33. {
  34. get
  35. {
  36. var name = ((Identifier) _expression).Name;
  37. return name is "eval" or "arguments";
  38. }
  39. }
  40. protected override object EvaluateInternal(EvaluationContext context)
  41. {
  42. if (!_initialized)
  43. {
  44. Initialize();
  45. _initialized = true;
  46. }
  47. var engine = context.Engine;
  48. var env = engine.ExecutionContext.LexicalEnvironment;
  49. var strict = StrictModeScope.IsStrictModeCode;
  50. var identifierEnvironment = JintEnvironment.TryGetIdentifierEnvironmentWithBinding(env, _identifier, out var temp)
  51. ? temp
  52. : JsValue.Undefined;
  53. return engine._referencePool.Rent(identifierEnvironment, _identifier.Value, strict, thisValue: null);
  54. }
  55. public override JsValue GetValue(EvaluationContext context)
  56. {
  57. // need to notify correct node when taking shortcut
  58. context.LastSyntaxElement = _expression;
  59. var identifier = Identifier;
  60. if (identifier.CalculatedValue is not null)
  61. {
  62. return identifier.CalculatedValue;
  63. }
  64. var strict = StrictModeScope.IsStrictModeCode;
  65. var engine = context.Engine;
  66. var env = engine.ExecutionContext.LexicalEnvironment;
  67. if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
  68. env,
  69. identifier,
  70. strict,
  71. out _,
  72. out var value))
  73. {
  74. if (value is null)
  75. {
  76. ThrowNotInitialized(engine);
  77. }
  78. }
  79. else
  80. {
  81. var reference = engine._referencePool.Rent(JsValue.Undefined, identifier.Value, strict, thisValue: null);
  82. value = engine.GetValue(reference, true);
  83. }
  84. // make sure arguments access freezes state
  85. if (value is JsArguments argumentsInstance)
  86. {
  87. argumentsInstance.Materialize();
  88. }
  89. return value;
  90. }
  91. [DoesNotReturn]
  92. [MethodImpl(MethodImplOptions.NoInlining)]
  93. private void ThrowNotInitialized(Engine engine)
  94. {
  95. ExceptionHelper.ThrowReferenceError(engine.Realm, $"{_identifier.Key.Name} has not been initialized");
  96. }
  97. }