protected override Completion ExecuteInternal(EvaluationContext context) { var jsValue = _object.GetValue(context).Value; var engine = context.Engine; var obj = TypeConverter.ToObject(engine.Realm, jsValue); var oldEnv = engine.ExecutionContext.LexicalEnvironment; var newEnv = JintEnvironment.NewObjectEnvironment(engine, obj, oldEnv, provideThis: true, withEnvironment: true); engine.UpdateLexicalEnvironment(newEnv); Completion c; try { c = _body.Execute(context); } catch (JavaScriptException e) { c = new Completion(CompletionType.Throw, e.Error, _statement.Location); } finally { engine.UpdateLexicalEnvironment(oldEnv); } return(c); }
protected override ExpressionResult EvaluateInternal(EvaluationContext context) { var engine = context.Engine; var env = engine.ExecutionContext.LexicalEnvironment; var strict = StrictModeScope.IsStrictModeCode; var identifierEnvironment = JintEnvironment.TryGetIdentifierEnvironmentWithBinding(env, _expressionName, out var temp) ? temp : JsValue.Undefined; return(NormalCompletion(engine._referencePool.Rent(identifierEnvironment, _expressionName.StringValue, strict, thisValue: null))); }
protected override Completion ExecuteInternal(EvaluationContext context) { EnvironmentRecord oldEnv = null; EnvironmentRecord loopEnv = null; var engine = context.Engine; if (_boundNames != null) { oldEnv = engine.ExecutionContext.LexicalEnvironment; loopEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); var loopEnvRec = loopEnv; var kind = _initStatement._statement.Kind; for (var i = 0; i < _boundNames.Count; i++) { var name = _boundNames[i]; if (kind == VariableDeclarationKind.Const) { loopEnvRec.CreateImmutableBinding(name, true); } else { loopEnvRec.CreateMutableBinding(name, false); } } engine.UpdateLexicalEnvironment(loopEnv); } try { if (_initExpression != null) { _initExpression?.GetValue(context); } else { _initStatement?.Execute(context); } return(ForBodyEvaluation(context)); } finally { if (oldEnv is not null) { engine.UpdateLexicalEnvironment(oldEnv); } } }
public override Completion GetValue(EvaluationContext context) { var engine = context.Engine; var funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment); var closure = new ScriptFunctionInstance( engine, _function, funcEnv, _function.ThisMode); closure.MakeConstructor(); if (_function.Name != null) { funcEnv.CreateMutableBindingAndInitialize(_function.Name, canBeDeleted: false, closure); } return(Completion.Normal(closure, _expression.Location)); }
public override Completion GetValue(EvaluationContext context) { // need to notify correct node when taking shortcut context.LastSyntaxNode = _expression; if (_calculatedValue is not null) { return(Completion.Normal(_calculatedValue, _expression.Location)); } var strict = StrictModeScope.IsStrictModeCode; var engine = context.Engine; var env = engine.ExecutionContext.LexicalEnvironment; if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue( env, _expressionName, strict, out _, out var value)) { if (value is null) { ExceptionHelper.ThrowReferenceError(engine.Realm, _expressionName.Key.Name + " has not been initialized"); } } else { var reference = engine._referencePool.Rent(JsValue.Undefined, _expressionName.StringValue, strict, thisValue: null); value = engine.GetValue(reference, true); } // make sure arguments access freezes state if (value is ArgumentsInstance argumentsInstance) { argumentsInstance.Materialize(); } return(Completion.Normal(value, _expression.Location)); }
protected override Completion ExecuteInternal(EvaluationContext context) { EnvironmentRecord oldEnv = null; var engine = context.Engine; if (_lexicalDeclarations != null) { oldEnv = engine.ExecutionContext.LexicalEnvironment; var blockEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment); JintStatementList.BlockDeclarationInstantiation(engine, blockEnv, _lexicalDeclarations); engine.UpdateLexicalEnvironment(blockEnv); } var blockValue = _statementList.Execute(context); if (oldEnv is not null) { engine.UpdateLexicalEnvironment(oldEnv); } return(blockValue); }
private void CreatePerIterationEnvironment(EvaluationContext context) { if (_boundNames == null || _boundNames.Count == 0) { return; } var engine = context.Engine; var lastIterationEnv = engine.ExecutionContext.LexicalEnvironment; var lastIterationEnvRec = lastIterationEnv; var outer = lastIterationEnv._outerEnv; var thisIterationEnv = JintEnvironment.NewDeclarativeEnvironment(engine, outer); for (var j = 0; j < _boundNames.Count; j++) { var bn = _boundNames[j]; var lastValue = lastIterationEnvRec.GetBindingValue(bn, true); thisIterationEnv.CreateMutableBindingAndInitialize(bn, false, lastValue); } engine.UpdateLexicalEnvironment(thisIterationEnv); }
internal static ExpressionResult?AssignToIdentifier( EvaluationContext context, JintIdentifierExpression left, JintExpression right, bool hasEvalOrArguments) { var engine = context.Engine; var env = engine.ExecutionContext.LexicalEnvironment; var strict = StrictModeScope.IsStrictModeCode; if (JintEnvironment.TryGetIdentifierEnvironmentWithBinding( env, left._expressionName, out var environmentRecord)) { if (strict && hasEvalOrArguments) { ExceptionHelper.ThrowSyntaxError(engine.Realm); } var completion = right.GetValue(context); if (completion.IsAbrupt()) { return(completion); } var rval = completion.Value.Clone(); if (right._expression.IsFunctionDefinition()) { ((FunctionInstance)rval).SetFunctionName(left._expressionName.StringValue); } environmentRecord.SetMutableBinding(left._expressionName, rval, strict); return(new Completion(CompletionType.Normal, rval, default)); } return(null); }
/// <summary> /// https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofheadevaluation-tdznames-expr-iterationkind /// </summary> private bool HeadEvaluation(EvaluationContext context, out IteratorInstance result) { var engine = context.Engine; var oldEnv = engine.ExecutionContext.LexicalEnvironment; var tdz = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); if (_tdzNames != null) { var TDZEnvRec = tdz; foreach (var name in _tdzNames) { TDZEnvRec.CreateMutableBinding(name); } } engine.UpdateLexicalEnvironment(tdz); var exprValue = _right.GetValue(context).Value; engine.UpdateLexicalEnvironment(oldEnv); if (_iterationKind == IterationKind.Enumerate) { if (exprValue.IsNullOrUndefined()) { result = null; return(false); } var obj = TypeConverter.ToObject(engine.Realm, exprValue); result = new ObjectKeyVisitor(engine, obj); } else { result = exprValue as IteratorInstance ?? exprValue.GetIterator(engine.Realm); } return(true); }
public Completion Execute(EvaluationContext context, JsValue input) { if (!_initialized) { Initialize(context); _initialized = true; } var engine = context.Engine; JsValue v = Undefined.Instance; Location l = context.LastSyntaxNode.Location; JintSwitchCase defaultCase = null; bool hit = false; for (var i = 0; i < (uint)_jintSwitchBlock.Length; i++) { var clause = _jintSwitchBlock[i]; EnvironmentRecord oldEnv = null; if (clause.LexicalDeclarations != null) { oldEnv = engine.ExecutionContext.LexicalEnvironment; var blockEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); JintStatementList.BlockDeclarationInstantiation(engine, blockEnv, clause.LexicalDeclarations); engine.UpdateLexicalEnvironment(blockEnv); } if (clause.Test == null) { defaultCase = clause; } else { var clauseSelector = clause.Test.GetValue(context).Value; if (clauseSelector == input) { hit = true; } } if (hit && clause.Consequent != null) { var r = clause.Consequent.Execute(context); if (oldEnv is not null) { engine.UpdateLexicalEnvironment(oldEnv); } if (r.Type != CompletionType.Normal) { return(r); } l = r.Location; v = r.Value ?? Undefined.Instance; } } // do we need to execute the default case ? if (hit == false && defaultCase != null) { EnvironmentRecord oldEnv = null; if (defaultCase.LexicalDeclarations != null) { oldEnv = engine.ExecutionContext.LexicalEnvironment; var blockEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); JintStatementList.BlockDeclarationInstantiation(engine, blockEnv, defaultCase.LexicalDeclarations); engine.UpdateLexicalEnvironment(blockEnv); } var r = defaultCase.Consequent.Execute(context); if (oldEnv is not null) { engine.UpdateLexicalEnvironment(oldEnv); } if (r.Type != CompletionType.Normal) { return(r); } l = r.Location; v = r.Value ?? Undefined.Instance; } return(new Completion(CompletionType.Normal, v, null, l)); }
/// <summary> /// https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset /// </summary> private Completion BodyEvaluation( EvaluationContext context, JintExpression lhs, JintStatement stmt, IteratorInstance iteratorRecord, IterationKind iterationKind, LhsKind lhsKind, IteratorKind iteratorKind = IteratorKind.Sync) { var engine = context.Engine; var oldEnv = engine.ExecutionContext.LexicalEnvironment; var v = Undefined.Instance; var destructuring = _destructuring; string lhsName = null; var completionType = CompletionType.Normal; var close = false; try { while (true) { EnvironmentRecord iterationEnv = null; if (!iteratorRecord.TryIteratorStep(out var nextResult)) { close = true; return(new Completion(CompletionType.Normal, v, null, Location)); } if (iteratorKind == IteratorKind.Async) { // nextResult = await nextResult; ExceptionHelper.ThrowNotImplementedException("await"); } var nextValue = nextResult.Get(CommonProperties.Value); close = true; var lhsRef = new ExpressionResult(); if (lhsKind != LhsKind.LexicalBinding) { if (!destructuring) { lhsRef = lhs.Evaluate(context); } } else { iterationEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv); if (_tdzNames != null) { BindingInstantiation(iterationEnv); } engine.UpdateLexicalEnvironment(iterationEnv); if (!destructuring) { var identifier = (Identifier)((VariableDeclaration)_leftNode).Declarations[0].Id; lhsName ??= identifier.Name; lhsRef = new ExpressionResult(ExpressionCompletionType.Normal, engine.ResolveBinding(lhsName), identifier.Location); } } if (context.DebugMode) { context.Engine.DebugHandler.OnStep(_leftNode); } var status = new Completion(); if (!destructuring) { if (lhsRef.IsAbrupt()) { close = true; status = new Completion(lhsRef); } else if (lhsKind == LhsKind.LexicalBinding) { ((Reference)lhsRef.Value).InitializeReferencedBinding(nextValue); } else { engine.PutValue((Reference)lhsRef.Value, nextValue); } } else { status = BindingPatternAssignmentExpression.ProcessPatterns( context, _assignmentPattern, nextValue, iterationEnv, checkObjectPatternPropertyReference: _lhsKind != LhsKind.VarBinding); if (lhsKind == LhsKind.Assignment) { // DestructuringAssignmentEvaluation of assignmentPattern using nextValue as the argument. } else if (lhsKind == LhsKind.VarBinding) { // BindingInitialization for lhs passing nextValue and undefined as the arguments. } else { // BindingInitialization for lhs passing nextValue and iterationEnv as arguments } } if (status.IsAbrupt()) { engine.UpdateLexicalEnvironment(oldEnv); if (_iterationKind == IterationKind.AsyncIterate) { iteratorRecord.Close(status.Type); return(status); } if (iterationKind == IterationKind.Enumerate) { return(status); } iteratorRecord.Close(status.Type); return(status); } var result = stmt.Execute(context); engine.UpdateLexicalEnvironment(oldEnv); if (!ReferenceEquals(result.Value, null)) { v = result.Value; } if (result.Type == CompletionType.Break && (result.Target == null || result.Target == _statement?.LabelSet?.Name)) { completionType = CompletionType.Normal; return(new Completion(CompletionType.Normal, v, null, Location)); } if (result.Type != CompletionType.Continue || (result.Target != null && result.Target != _statement?.LabelSet?.Name)) { completionType = result.Type; if (result.IsAbrupt()) { close = true; return(result); } } } } catch { completionType = CompletionType.Throw; throw; } finally { if (close) { try { iteratorRecord.Close(completionType); } catch { // if we already have and exception, use it if (completionType != CompletionType.Throw) { throw; } } } engine.UpdateLexicalEnvironment(oldEnv); } }
/// <summary> /// https://tc39.es/ecma262/#sec-performeval /// </summary> public JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bool direct) { if (!x.IsString()) { return(x); } var evalRealm = _realm; _engine._host.EnsureCanCompileStrings(callerRealm, evalRealm); var inFunction = false; var inMethod = false; var inDerivedConstructor = false; if (direct) { var thisEnvRec = _engine.ExecutionContext.GetThisEnvironment(); if (thisEnvRec is FunctionEnvironmentRecord functionEnvironmentRecord) { var F = functionEnvironmentRecord._functionObject; inFunction = true; inMethod = thisEnvRec.HasSuperBinding(); if (F._constructorKind == ConstructorKind.Derived) { inDerivedConstructor = true; } } } var parser = new JavaScriptParser(x.ToString(), ParserOptions); Script script = null; try { script = parser.ParseScript(strictCaller); } catch (ParserException e) { if (e.Description == Messages.InvalidLHSInAssignment) { ExceptionHelper.ThrowReferenceError(callerRealm, (string)null); } else { ExceptionHelper.ThrowSyntaxError(callerRealm, e.Message); } } var body = script.Body; if (body.Count == 0) { return(Undefined); } if (!inFunction) { // if body Contains NewTarget, throw a SyntaxError exception. } if (!inMethod) { // if body Contains SuperProperty, throw a SyntaxError exception. } if (!inDerivedConstructor) { // if body Contains SuperCall, throw a SyntaxError exception. } var strictEval = script.Strict || _engine._isStrict; var ctx = _engine.ExecutionContext; using (new StrictModeScope(strictEval)) { EnvironmentRecord lexEnv; EnvironmentRecord varEnv; PrivateEnvironmentRecord privateEnv; if (direct) { lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, ctx.LexicalEnvironment); varEnv = ctx.VariableEnvironment; privateEnv = ctx.PrivateEnvironment; } else { lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, evalRealm.GlobalEnv); varEnv = evalRealm.GlobalEnv; privateEnv = null; } if (strictEval) { varEnv = lexEnv; } // If ctx is not already suspended, suspend ctx. Engine.EnterExecutionContext(lexEnv, varEnv, evalRealm, privateEnv); try { Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, privateEnv, strictEval); var statement = new JintScript(script); var result = statement.Execute(_engine._activeEvaluationContext); var value = result.GetValueOrDefault(); if (result.Type == CompletionType.Throw) { var ex = new JavaScriptException(value).SetCallstack(_engine, result.Location); throw ex; } else { return(value); } } finally { Engine.LeaveExecutionContext(); } } }
/// <summary> /// https://tc39.es/ecma262/#sec-source-text-module-record-initialize-environment /// </summary> protected override void InitializeEnvironment() { for (var i = 0; i < _indirectExportEntries.Count; i++) { var e = _indirectExportEntries[i]; var resolution = ResolveExport(e.ExportName); if (resolution is null || resolution == ResolvedBinding.Ambiguous) { ExceptionHelper.ThrowSyntaxError(_realm, "Ambiguous import statement for identifier: " + e.ExportName); } } var realm = _realm; var env = JintEnvironment.NewModuleEnvironment(_engine, realm.GlobalEnv); _environment = env; if (_importEntries != null) { for (var i = 0; i < _importEntries.Count; i++) { var ie = _importEntries[i]; var importedModule = _engine._host.ResolveImportedModule(this, ie.ModuleRequest); if (ie.ImportName == "*") { var ns = GetModuleNamespace(importedModule); env.CreateImmutableBinding(ie.LocalName, true); env.InitializeBinding(ie.LocalName, ns); } else { var resolution = importedModule.ResolveExport(ie.ImportName); if (resolution is null || resolution == ResolvedBinding.Ambiguous) { ExceptionHelper.ThrowSyntaxError(_realm, "Ambiguous import statement for identifier " + ie.ImportName); } if (resolution.BindingName == "*namespace*") { var ns = GetModuleNamespace(resolution.Module); env.CreateImmutableBinding(ie.LocalName, true); env.InitializeBinding(ie.LocalName, ns); } else { env.CreateImportBinding(ie.LocalName, resolution.Module, resolution.BindingName); } } } } var moduleContext = new ExecutionContext(this, _environment, _environment, null, realm, null); _context = moduleContext; _engine.EnterExecutionContext(_context); var hoistingScope = HoistingScope.GetModuleLevelDeclarations(_source); var varDeclarations = hoistingScope._variablesDeclarations; var declaredVarNames = new HashSet <string>(); if (varDeclarations != null) { var boundNames = new List <string>(); for (var i = 0; i < varDeclarations.Count; i++) { var d = varDeclarations[i]; boundNames.Clear(); d.GetBoundNames(boundNames); for (var j = 0; j < boundNames.Count; j++) { var dn = boundNames[j]; if (declaredVarNames.Add(dn)) { env.CreateMutableBinding(dn, false); env.InitializeBinding(dn, Undefined); } } } } var lexDeclarations = hoistingScope._lexicalDeclarations; if (lexDeclarations != null) { var boundNames = new List <string>(); for (var i = 0; i < lexDeclarations.Count; i++) { var d = lexDeclarations[i]; boundNames.Clear(); d.GetBoundNames(boundNames); for (var j = 0; j < boundNames.Count; j++) { var dn = boundNames[j]; if (d.IsConstantDeclaration()) { env.CreateImmutableBinding(dn, true); } else { env.CreateMutableBinding(dn, false); } } } } var functionDeclarations = hoistingScope._functionDeclarations; if (functionDeclarations != null) { for (var i = 0; i < functionDeclarations.Count; i++) { var d = functionDeclarations[i]; var fn = d.Id?.Name ?? "*default*"; var fd = new JintFunctionDefinition(_engine, d); env.CreateMutableBinding(fn, true); var fo = realm.Intrinsics.Function.InstantiateFunctionObject(fd, env); if (fn == "*default*") { fo.SetFunctionName("default"); } env.InitializeBinding(fn, fo); } } _engine.LeaveExecutionContext(); }
protected override Completion ExecuteInternal(EvaluationContext context) { var engine = context.Engine; int callStackSizeBeforeExecution = engine.CallStack.Count; var b = _block.Execute(context); if (b.Type == CompletionType.Throw) { // initialize lazily if (_statement.Handler is not null && _catch is null) { _catch = Build(_statement.Handler.Body); } // execute catch if (_statement.Handler is not null) { // Quick-patch for call stack not being unwinded when an exception is caught. // Ideally, this should instead be solved by always popping the stack when returning // from a call, regardless of whether it throws (i.e. CallStack.Pop() in finally clause // in Engine.Call/Engine.Construct - however, that method currently breaks stack traces // in error messages. while (callStackSizeBeforeExecution < engine.CallStack.Count) { engine.CallStack.Pop(); } // https://tc39.es/ecma262/#sec-runtime-semantics-catchclauseevaluation var thrownValue = b.Value; var oldEnv = engine.ExecutionContext.LexicalEnvironment; var catchEnv = JintEnvironment.NewDeclarativeEnvironment(engine, oldEnv, catchEnvironment: true); var boundNames = new List <string>(); _statement.Handler.Param.GetBoundNames(boundNames); foreach (var argName in boundNames) { catchEnv.CreateMutableBinding(argName, false); } engine.UpdateLexicalEnvironment(catchEnv); var catchParam = _statement.Handler?.Param; catchParam.BindingInitialization(context, thrownValue, catchEnv); b = _catch.Execute(context); engine.UpdateLexicalEnvironment(oldEnv); } } if (_finalizer != null) { var f = _finalizer.Execute(context); if (f.Type == CompletionType.Normal) { return(b); } return(f.UpdateEmpty(Undefined.Instance)); } return(b.UpdateEmpty(Undefined.Instance)); }
protected override ExpressionResult EvaluateInternal(EvaluationContext context) { JsValue actualThis = null; string baseReferenceName = null; JsValue baseValue = null; var isStrictModeCode = StrictModeScope.IsStrictModeCode; var engine = context.Engine; if (_objectExpression is JintIdentifierExpression identifierExpression) { baseReferenceName = identifierExpression._expressionName.Key.Name; var strict = isStrictModeCode; var env = engine.ExecutionContext.LexicalEnvironment; JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue( env, identifierExpression._expressionName, strict, out _, out baseValue); } else if (_objectExpression is JintThisExpression thisExpression) { baseValue = thisExpression.GetValue(context).Value; } else if (_objectExpression is JintSuperExpression) { var env = (FunctionEnvironmentRecord)engine.ExecutionContext.GetThisEnvironment(); actualThis = env.GetThisBinding(); baseValue = env.GetSuperBase(); } if (baseValue is null) { // fast checks failed var baseReference = _objectExpression.Evaluate(context).Value; if (ReferenceEquals(Undefined.Instance, baseReference)) { return(NormalCompletion(Undefined.Instance)); } if (baseReference is Reference reference) { baseReferenceName = reference.GetReferencedName().ToString(); baseValue = engine.GetValue(reference, false); engine._referencePool.Return(reference); } else { baseValue = engine.GetValue(baseReference, false); } } if (baseValue.IsNullOrUndefined() && (_memberExpression.Optional || _objectExpression._expression.IsOptional())) { return(NormalCompletion(Undefined.Instance)); } var property = _determinedProperty ?? _propertyExpression.GetValue(context).Value; if (baseValue.IsNullOrUndefined()) { // we can use base data types securely, object evaluation can mess things up var referenceName = property.IsPrimitive() ? TypeConverter.ToString(property) : _determinedProperty?.ToString() ?? baseReferenceName; TypeConverter.CheckObjectCoercible(engine, baseValue, _memberExpression.Property, referenceName); } // only convert if necessary var propertyKey = property.IsInteger() && baseValue.IsIntegerIndexedArray ? property : TypeConverter.ToPropertyKey(property); var rent = context.Engine._referencePool.Rent(baseValue, propertyKey, isStrictModeCode, thisValue: actualThis); return(new ExpressionResult( ExpressionCompletionType.Reference, rent, _expression.Location)); }
private JsValue UpdateIdentifier(EvaluationContext context) { var strict = StrictModeScope.IsStrictModeCode; var name = _leftIdentifier._expressionName; var engine = context.Engine; var env = engine.ExecutionContext.LexicalEnvironment; if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue( env, name, strict, out var environmentRecord, out var value)) { if (strict && _evalOrArguments) { ExceptionHelper.ThrowSyntaxError(engine.Realm); } var isInteger = value._type == InternalTypes.Integer; JsValue newValue = null; var operatorOverloaded = false; if (context.OperatorOverloadingAllowed) { if (JintUnaryExpression.TryOperatorOverloading(context, _argument.GetValue(context).Value, _change > 0 ? "op_Increment" : "op_Decrement", out var result)) { operatorOverloaded = true; newValue = result; } } if (!operatorOverloaded) { if (isInteger) { newValue = JsNumber.Create(value.AsInteger() + _change); } else if (value._type != InternalTypes.BigInt) { newValue = JsNumber.Create(TypeConverter.ToNumber(value) + _change); } else { newValue = JsBigInt.Create(TypeConverter.ToBigInt(value) + _change); } } environmentRecord.SetMutableBinding(name.Key.Name, newValue, strict); if (_prefix) { return(newValue); } if (!value.IsBigInt() && !value.IsNumber() && !operatorOverloaded) { return(JsNumber.Create(TypeConverter.ToNumber(value))); } return(value); } return(null); }