JintIdentifierExpression.cs 3.2 KB

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