11cb0ef41Sopenharmony_ci// Copyright 2015 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-generator.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <map> 81cb0ef41Sopenharmony_ci#include <unordered_map> 91cb0ef41Sopenharmony_ci#include <unordered_set> 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci#include "include/v8-extension.h" 121cb0ef41Sopenharmony_ci#include "src/api/api-inl.h" 131cb0ef41Sopenharmony_ci#include "src/ast/ast-source-ranges.h" 141cb0ef41Sopenharmony_ci#include "src/ast/ast.h" 151cb0ef41Sopenharmony_ci#include "src/ast/scopes.h" 161cb0ef41Sopenharmony_ci#include "src/builtins/builtins-constructor.h" 171cb0ef41Sopenharmony_ci#include "src/codegen/compiler.h" 181cb0ef41Sopenharmony_ci#include "src/codegen/unoptimized-compilation-info.h" 191cb0ef41Sopenharmony_ci#include "src/common/globals.h" 201cb0ef41Sopenharmony_ci#include "src/compiler-dispatcher/lazy-compile-dispatcher.h" 211cb0ef41Sopenharmony_ci#include "src/heap/parked-scope.h" 221cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-flags.h" 231cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-jump-table.h" 241cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-label.h" 251cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-register-allocator.h" 261cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-register.h" 271cb0ef41Sopenharmony_ci#include "src/interpreter/control-flow-builders.h" 281cb0ef41Sopenharmony_ci#include "src/logging/local-logger.h" 291cb0ef41Sopenharmony_ci#include "src/logging/log.h" 301cb0ef41Sopenharmony_ci#include "src/numbers/conversions.h" 311cb0ef41Sopenharmony_ci#include "src/objects/debug-objects.h" 321cb0ef41Sopenharmony_ci#include "src/objects/literal-objects-inl.h" 331cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 341cb0ef41Sopenharmony_ci#include "src/objects/smi.h" 351cb0ef41Sopenharmony_ci#include "src/objects/template-objects-inl.h" 361cb0ef41Sopenharmony_ci#include "src/parsing/parse-info.h" 371cb0ef41Sopenharmony_ci#include "src/parsing/token.h" 381cb0ef41Sopenharmony_ci#include "src/utils/ostreams.h" 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_cinamespace v8 { 411cb0ef41Sopenharmony_cinamespace internal { 421cb0ef41Sopenharmony_cinamespace interpreter { 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci// Scoped class tracking context objects created by the visitor. Represents 451cb0ef41Sopenharmony_ci// mutations of the context chain within the function body, allowing pushing and 461cb0ef41Sopenharmony_ci// popping of the current {context_register} during visitation. 471cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::ContextScope { 481cb0ef41Sopenharmony_ci public: 491cb0ef41Sopenharmony_ci ContextScope(BytecodeGenerator* generator, Scope* scope, 501cb0ef41Sopenharmony_ci Register outer_context_reg = Register()) 511cb0ef41Sopenharmony_ci : generator_(generator), 521cb0ef41Sopenharmony_ci scope_(scope), 531cb0ef41Sopenharmony_ci outer_(generator_->execution_context()), 541cb0ef41Sopenharmony_ci register_(Register::current_context()), 551cb0ef41Sopenharmony_ci depth_(0) { 561cb0ef41Sopenharmony_ci DCHECK(scope->NeedsContext() || outer_ == nullptr); 571cb0ef41Sopenharmony_ci if (outer_) { 581cb0ef41Sopenharmony_ci depth_ = outer_->depth_ + 1; 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci // Push the outer context into a new context register. 611cb0ef41Sopenharmony_ci if (!outer_context_reg.is_valid()) { 621cb0ef41Sopenharmony_ci outer_context_reg = generator_->register_allocator()->NewRegister(); 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci outer_->set_register(outer_context_reg); 651cb0ef41Sopenharmony_ci generator_->builder()->PushContext(outer_context_reg); 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci generator_->set_execution_context(this); 681cb0ef41Sopenharmony_ci } 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci ~ContextScope() { 711cb0ef41Sopenharmony_ci if (outer_) { 721cb0ef41Sopenharmony_ci DCHECK_EQ(register_.index(), Register::current_context().index()); 731cb0ef41Sopenharmony_ci generator_->builder()->PopContext(outer_->reg()); 741cb0ef41Sopenharmony_ci outer_->set_register(register_); 751cb0ef41Sopenharmony_ci } 761cb0ef41Sopenharmony_ci generator_->set_execution_context(outer_); 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci ContextScope(const ContextScope&) = delete; 801cb0ef41Sopenharmony_ci ContextScope& operator=(const ContextScope&) = delete; 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci // Returns the depth of the given |scope| for the current execution context. 831cb0ef41Sopenharmony_ci int ContextChainDepth(Scope* scope) { 841cb0ef41Sopenharmony_ci return scope_->ContextChainLength(scope); 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci // Returns the execution context at |depth| in the current context chain if it 881cb0ef41Sopenharmony_ci // is a function local execution context, otherwise returns nullptr. 891cb0ef41Sopenharmony_ci ContextScope* Previous(int depth) { 901cb0ef41Sopenharmony_ci if (depth > depth_) { 911cb0ef41Sopenharmony_ci return nullptr; 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ci ContextScope* previous = this; 951cb0ef41Sopenharmony_ci for (int i = depth; i > 0; --i) { 961cb0ef41Sopenharmony_ci previous = previous->outer_; 971cb0ef41Sopenharmony_ci } 981cb0ef41Sopenharmony_ci return previous; 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci Register reg() const { return register_; } 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci private: 1041cb0ef41Sopenharmony_ci const BytecodeArrayBuilder* builder() const { return generator_->builder(); } 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci void set_register(Register reg) { register_ = reg; } 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci BytecodeGenerator* generator_; 1091cb0ef41Sopenharmony_ci Scope* scope_; 1101cb0ef41Sopenharmony_ci ContextScope* outer_; 1111cb0ef41Sopenharmony_ci Register register_; 1121cb0ef41Sopenharmony_ci int depth_; 1131cb0ef41Sopenharmony_ci}; 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci// Scoped class for tracking control statements entered by the 1161cb0ef41Sopenharmony_ci// visitor. 1171cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::ControlScope { 1181cb0ef41Sopenharmony_ci public: 1191cb0ef41Sopenharmony_ci explicit ControlScope(BytecodeGenerator* generator) 1201cb0ef41Sopenharmony_ci : generator_(generator), 1211cb0ef41Sopenharmony_ci outer_(generator->execution_control()), 1221cb0ef41Sopenharmony_ci context_(generator->execution_context()) { 1231cb0ef41Sopenharmony_ci generator_->set_execution_control(this); 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci ~ControlScope() { generator_->set_execution_control(outer()); } 1261cb0ef41Sopenharmony_ci ControlScope(const ControlScope&) = delete; 1271cb0ef41Sopenharmony_ci ControlScope& operator=(const ControlScope&) = delete; 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci void Break(Statement* stmt) { 1301cb0ef41Sopenharmony_ci PerformCommand(CMD_BREAK, stmt, kNoSourcePosition); 1311cb0ef41Sopenharmony_ci } 1321cb0ef41Sopenharmony_ci void Continue(Statement* stmt) { 1331cb0ef41Sopenharmony_ci PerformCommand(CMD_CONTINUE, stmt, kNoSourcePosition); 1341cb0ef41Sopenharmony_ci } 1351cb0ef41Sopenharmony_ci void ReturnAccumulator(int source_position) { 1361cb0ef41Sopenharmony_ci PerformCommand(CMD_RETURN, nullptr, source_position); 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci void AsyncReturnAccumulator(int source_position) { 1391cb0ef41Sopenharmony_ci PerformCommand(CMD_ASYNC_RETURN, nullptr, source_position); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci class DeferredCommands; 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci protected: 1451cb0ef41Sopenharmony_ci enum Command { 1461cb0ef41Sopenharmony_ci CMD_BREAK, 1471cb0ef41Sopenharmony_ci CMD_CONTINUE, 1481cb0ef41Sopenharmony_ci CMD_RETURN, 1491cb0ef41Sopenharmony_ci CMD_ASYNC_RETURN, 1501cb0ef41Sopenharmony_ci CMD_RETHROW 1511cb0ef41Sopenharmony_ci }; 1521cb0ef41Sopenharmony_ci static constexpr bool CommandUsesAccumulator(Command command) { 1531cb0ef41Sopenharmony_ci return command != CMD_BREAK && command != CMD_CONTINUE; 1541cb0ef41Sopenharmony_ci } 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci void PerformCommand(Command command, Statement* statement, 1571cb0ef41Sopenharmony_ci int source_position); 1581cb0ef41Sopenharmony_ci virtual bool Execute(Command command, Statement* statement, 1591cb0ef41Sopenharmony_ci int source_position) = 0; 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci // Helper to pop the context chain to a depth expected by this control scope. 1621cb0ef41Sopenharmony_ci // Note that it is the responsibility of each individual {Execute} method to 1631cb0ef41Sopenharmony_ci // trigger this when commands are handled and control-flow continues locally. 1641cb0ef41Sopenharmony_ci void PopContextToExpectedDepth(); 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci BytecodeGenerator* generator() const { return generator_; } 1671cb0ef41Sopenharmony_ci ControlScope* outer() const { return outer_; } 1681cb0ef41Sopenharmony_ci ContextScope* context() const { return context_; } 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci private: 1711cb0ef41Sopenharmony_ci BytecodeGenerator* generator_; 1721cb0ef41Sopenharmony_ci ControlScope* outer_; 1731cb0ef41Sopenharmony_ci ContextScope* context_; 1741cb0ef41Sopenharmony_ci}; 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci// Helper class for a try-finally control scope. It can record intercepted 1771cb0ef41Sopenharmony_ci// control-flow commands that cause entry into a finally-block, and re-apply 1781cb0ef41Sopenharmony_ci// them after again leaving that block. Special tokens are used to identify 1791cb0ef41Sopenharmony_ci// paths going through the finally-block to dispatch after leaving the block. 1801cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::ControlScope::DeferredCommands final { 1811cb0ef41Sopenharmony_ci public: 1821cb0ef41Sopenharmony_ci // Fixed value tokens for paths we know we need. 1831cb0ef41Sopenharmony_ci // Fallthrough is set to -1 to make it the fallthrough case of the jump table, 1841cb0ef41Sopenharmony_ci // where the remaining cases start at 0. 1851cb0ef41Sopenharmony_ci static const int kFallthroughToken = -1; 1861cb0ef41Sopenharmony_ci // TODO(leszeks): Rethrow being 0 makes it use up a valuable LdaZero, which 1871cb0ef41Sopenharmony_ci // means that other commands (such as break or return) have to use LdaSmi. 1881cb0ef41Sopenharmony_ci // This can very slightly bloat bytecode, so perhaps token values should all 1891cb0ef41Sopenharmony_ci // be shifted down by 1. 1901cb0ef41Sopenharmony_ci static const int kRethrowToken = 0; 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci DeferredCommands(BytecodeGenerator* generator, Register token_register, 1931cb0ef41Sopenharmony_ci Register result_register) 1941cb0ef41Sopenharmony_ci : generator_(generator), 1951cb0ef41Sopenharmony_ci deferred_(generator->zone()), 1961cb0ef41Sopenharmony_ci token_register_(token_register), 1971cb0ef41Sopenharmony_ci result_register_(result_register), 1981cb0ef41Sopenharmony_ci return_token_(-1), 1991cb0ef41Sopenharmony_ci async_return_token_(-1) { 2001cb0ef41Sopenharmony_ci // There's always a rethrow path. 2011cb0ef41Sopenharmony_ci // TODO(leszeks): We could decouple deferred_ index and token to allow us 2021cb0ef41Sopenharmony_ci // to still push this lazily. 2031cb0ef41Sopenharmony_ci STATIC_ASSERT(kRethrowToken == 0); 2041cb0ef41Sopenharmony_ci deferred_.push_back({CMD_RETHROW, nullptr, kRethrowToken}); 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci // One recorded control-flow command. 2081cb0ef41Sopenharmony_ci struct Entry { 2091cb0ef41Sopenharmony_ci Command command; // The command type being applied on this path. 2101cb0ef41Sopenharmony_ci Statement* statement; // The target statement for the command or {nullptr}. 2111cb0ef41Sopenharmony_ci int token; // A token identifying this particular path. 2121cb0ef41Sopenharmony_ci }; 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci // Records a control-flow command while entering the finally-block. This also 2151cb0ef41Sopenharmony_ci // generates a new dispatch token that identifies one particular path. This 2161cb0ef41Sopenharmony_ci // expects the result to be in the accumulator. 2171cb0ef41Sopenharmony_ci void RecordCommand(Command command, Statement* statement) { 2181cb0ef41Sopenharmony_ci int token = GetTokenForCommand(command, statement); 2191cb0ef41Sopenharmony_ci 2201cb0ef41Sopenharmony_ci DCHECK_LT(token, deferred_.size()); 2211cb0ef41Sopenharmony_ci DCHECK_EQ(deferred_[token].command, command); 2221cb0ef41Sopenharmony_ci DCHECK_EQ(deferred_[token].statement, statement); 2231cb0ef41Sopenharmony_ci DCHECK_EQ(deferred_[token].token, token); 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci if (CommandUsesAccumulator(command)) { 2261cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(result_register_); 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci builder()->LoadLiteral(Smi::FromInt(token)); 2291cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(token_register_); 2301cb0ef41Sopenharmony_ci if (!CommandUsesAccumulator(command)) { 2311cb0ef41Sopenharmony_ci // If we're not saving the accumulator in the result register, shove a 2321cb0ef41Sopenharmony_ci // harmless value there instead so that it is still considered "killed" in 2331cb0ef41Sopenharmony_ci // the liveness analysis. Normally we would LdaUndefined first, but the 2341cb0ef41Sopenharmony_ci // Smi token value is just as good, and by reusing it we save a bytecode. 2351cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(result_register_); 2361cb0ef41Sopenharmony_ci } 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci // Records the dispatch token to be used to identify the re-throw path when 2401cb0ef41Sopenharmony_ci // the finally-block has been entered through the exception handler. This 2411cb0ef41Sopenharmony_ci // expects the exception to be in the accumulator. 2421cb0ef41Sopenharmony_ci void RecordHandlerReThrowPath() { 2431cb0ef41Sopenharmony_ci // The accumulator contains the exception object. 2441cb0ef41Sopenharmony_ci RecordCommand(CMD_RETHROW, nullptr); 2451cb0ef41Sopenharmony_ci } 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_ci // Records the dispatch token to be used to identify the implicit fall-through 2481cb0ef41Sopenharmony_ci // path at the end of a try-block into the corresponding finally-block. 2491cb0ef41Sopenharmony_ci void RecordFallThroughPath() { 2501cb0ef41Sopenharmony_ci builder()->LoadLiteral(Smi::FromInt(kFallthroughToken)); 2511cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(token_register_); 2521cb0ef41Sopenharmony_ci // Since we're not saving the accumulator in the result register, shove a 2531cb0ef41Sopenharmony_ci // harmless value there instead so that it is still considered "killed" in 2541cb0ef41Sopenharmony_ci // the liveness analysis. Normally we would LdaUndefined first, but the Smi 2551cb0ef41Sopenharmony_ci // token value is just as good, and by reusing it we save a bytecode. 2561cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(result_register_); 2571cb0ef41Sopenharmony_ci } 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci // Applies all recorded control-flow commands after the finally-block again. 2601cb0ef41Sopenharmony_ci // This generates a dynamic dispatch on the token from the entry point. 2611cb0ef41Sopenharmony_ci void ApplyDeferredCommands() { 2621cb0ef41Sopenharmony_ci if (deferred_.size() == 0) return; 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci BytecodeLabel fall_through; 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ci if (deferred_.size() == 1) { 2671cb0ef41Sopenharmony_ci // For a single entry, just jump to the fallthrough if we don't match the 2681cb0ef41Sopenharmony_ci // entry token. 2691cb0ef41Sopenharmony_ci const Entry& entry = deferred_[0]; 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci builder() 2721cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromInt(entry.token)) 2731cb0ef41Sopenharmony_ci .CompareReference(token_register_) 2741cb0ef41Sopenharmony_ci .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &fall_through); 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci if (CommandUsesAccumulator(entry.command)) { 2771cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(result_register_); 2781cb0ef41Sopenharmony_ci } 2791cb0ef41Sopenharmony_ci execution_control()->PerformCommand(entry.command, entry.statement, 2801cb0ef41Sopenharmony_ci kNoSourcePosition); 2811cb0ef41Sopenharmony_ci } else { 2821cb0ef41Sopenharmony_ci // For multiple entries, build a jump table and switch on the token, 2831cb0ef41Sopenharmony_ci // jumping to the fallthrough if none of them match. 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci BytecodeJumpTable* jump_table = 2861cb0ef41Sopenharmony_ci builder()->AllocateJumpTable(static_cast<int>(deferred_.size()), 0); 2871cb0ef41Sopenharmony_ci builder() 2881cb0ef41Sopenharmony_ci ->LoadAccumulatorWithRegister(token_register_) 2891cb0ef41Sopenharmony_ci .SwitchOnSmiNoFeedback(jump_table) 2901cb0ef41Sopenharmony_ci .Jump(&fall_through); 2911cb0ef41Sopenharmony_ci for (const Entry& entry : deferred_) { 2921cb0ef41Sopenharmony_ci builder()->Bind(jump_table, entry.token); 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_ci if (CommandUsesAccumulator(entry.command)) { 2951cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(result_register_); 2961cb0ef41Sopenharmony_ci } 2971cb0ef41Sopenharmony_ci execution_control()->PerformCommand(entry.command, entry.statement, 2981cb0ef41Sopenharmony_ci kNoSourcePosition); 2991cb0ef41Sopenharmony_ci } 3001cb0ef41Sopenharmony_ci } 3011cb0ef41Sopenharmony_ci 3021cb0ef41Sopenharmony_ci builder()->Bind(&fall_through); 3031cb0ef41Sopenharmony_ci } 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_ci BytecodeArrayBuilder* builder() { return generator_->builder(); } 3061cb0ef41Sopenharmony_ci ControlScope* execution_control() { return generator_->execution_control(); } 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci private: 3091cb0ef41Sopenharmony_ci int GetTokenForCommand(Command command, Statement* statement) { 3101cb0ef41Sopenharmony_ci switch (command) { 3111cb0ef41Sopenharmony_ci case CMD_RETURN: 3121cb0ef41Sopenharmony_ci return GetReturnToken(); 3131cb0ef41Sopenharmony_ci case CMD_ASYNC_RETURN: 3141cb0ef41Sopenharmony_ci return GetAsyncReturnToken(); 3151cb0ef41Sopenharmony_ci case CMD_RETHROW: 3161cb0ef41Sopenharmony_ci return kRethrowToken; 3171cb0ef41Sopenharmony_ci default: 3181cb0ef41Sopenharmony_ci // TODO(leszeks): We could also search for entries with the same 3191cb0ef41Sopenharmony_ci // command and statement. 3201cb0ef41Sopenharmony_ci return GetNewTokenForCommand(command, statement); 3211cb0ef41Sopenharmony_ci } 3221cb0ef41Sopenharmony_ci } 3231cb0ef41Sopenharmony_ci 3241cb0ef41Sopenharmony_ci int GetReturnToken() { 3251cb0ef41Sopenharmony_ci if (return_token_ == -1) { 3261cb0ef41Sopenharmony_ci return_token_ = GetNewTokenForCommand(CMD_RETURN, nullptr); 3271cb0ef41Sopenharmony_ci } 3281cb0ef41Sopenharmony_ci return return_token_; 3291cb0ef41Sopenharmony_ci } 3301cb0ef41Sopenharmony_ci 3311cb0ef41Sopenharmony_ci int GetAsyncReturnToken() { 3321cb0ef41Sopenharmony_ci if (async_return_token_ == -1) { 3331cb0ef41Sopenharmony_ci async_return_token_ = GetNewTokenForCommand(CMD_ASYNC_RETURN, nullptr); 3341cb0ef41Sopenharmony_ci } 3351cb0ef41Sopenharmony_ci return async_return_token_; 3361cb0ef41Sopenharmony_ci } 3371cb0ef41Sopenharmony_ci 3381cb0ef41Sopenharmony_ci int GetNewTokenForCommand(Command command, Statement* statement) { 3391cb0ef41Sopenharmony_ci int token = static_cast<int>(deferred_.size()); 3401cb0ef41Sopenharmony_ci deferred_.push_back({command, statement, token}); 3411cb0ef41Sopenharmony_ci return token; 3421cb0ef41Sopenharmony_ci } 3431cb0ef41Sopenharmony_ci 3441cb0ef41Sopenharmony_ci BytecodeGenerator* generator_; 3451cb0ef41Sopenharmony_ci ZoneVector<Entry> deferred_; 3461cb0ef41Sopenharmony_ci Register token_register_; 3471cb0ef41Sopenharmony_ci Register result_register_; 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci // Tokens for commands that don't need a statement. 3501cb0ef41Sopenharmony_ci int return_token_; 3511cb0ef41Sopenharmony_ci int async_return_token_; 3521cb0ef41Sopenharmony_ci}; 3531cb0ef41Sopenharmony_ci 3541cb0ef41Sopenharmony_ci// Scoped class for dealing with control flow reaching the function level. 3551cb0ef41Sopenharmony_ciclass BytecodeGenerator::ControlScopeForTopLevel final 3561cb0ef41Sopenharmony_ci : public BytecodeGenerator::ControlScope { 3571cb0ef41Sopenharmony_ci public: 3581cb0ef41Sopenharmony_ci explicit ControlScopeForTopLevel(BytecodeGenerator* generator) 3591cb0ef41Sopenharmony_ci : ControlScope(generator) {} 3601cb0ef41Sopenharmony_ci 3611cb0ef41Sopenharmony_ci protected: 3621cb0ef41Sopenharmony_ci bool Execute(Command command, Statement* statement, 3631cb0ef41Sopenharmony_ci int source_position) override { 3641cb0ef41Sopenharmony_ci switch (command) { 3651cb0ef41Sopenharmony_ci case CMD_BREAK: // We should never see break/continue in top-level. 3661cb0ef41Sopenharmony_ci case CMD_CONTINUE: 3671cb0ef41Sopenharmony_ci UNREACHABLE(); 3681cb0ef41Sopenharmony_ci case CMD_RETURN: 3691cb0ef41Sopenharmony_ci // No need to pop contexts, execution leaves the method body. 3701cb0ef41Sopenharmony_ci generator()->BuildReturn(source_position); 3711cb0ef41Sopenharmony_ci return true; 3721cb0ef41Sopenharmony_ci case CMD_ASYNC_RETURN: 3731cb0ef41Sopenharmony_ci // No need to pop contexts, execution leaves the method body. 3741cb0ef41Sopenharmony_ci generator()->BuildAsyncReturn(source_position); 3751cb0ef41Sopenharmony_ci return true; 3761cb0ef41Sopenharmony_ci case CMD_RETHROW: 3771cb0ef41Sopenharmony_ci // No need to pop contexts, execution leaves the method body. 3781cb0ef41Sopenharmony_ci generator()->BuildReThrow(); 3791cb0ef41Sopenharmony_ci return true; 3801cb0ef41Sopenharmony_ci } 3811cb0ef41Sopenharmony_ci return false; 3821cb0ef41Sopenharmony_ci } 3831cb0ef41Sopenharmony_ci}; 3841cb0ef41Sopenharmony_ci 3851cb0ef41Sopenharmony_ci// Scoped class for enabling break inside blocks and switch blocks. 3861cb0ef41Sopenharmony_ciclass BytecodeGenerator::ControlScopeForBreakable final 3871cb0ef41Sopenharmony_ci : public BytecodeGenerator::ControlScope { 3881cb0ef41Sopenharmony_ci public: 3891cb0ef41Sopenharmony_ci ControlScopeForBreakable(BytecodeGenerator* generator, 3901cb0ef41Sopenharmony_ci BreakableStatement* statement, 3911cb0ef41Sopenharmony_ci BreakableControlFlowBuilder* control_builder) 3921cb0ef41Sopenharmony_ci : ControlScope(generator), 3931cb0ef41Sopenharmony_ci statement_(statement), 3941cb0ef41Sopenharmony_ci control_builder_(control_builder) {} 3951cb0ef41Sopenharmony_ci 3961cb0ef41Sopenharmony_ci protected: 3971cb0ef41Sopenharmony_ci bool Execute(Command command, Statement* statement, 3981cb0ef41Sopenharmony_ci int source_position) override { 3991cb0ef41Sopenharmony_ci if (statement != statement_) return false; 4001cb0ef41Sopenharmony_ci switch (command) { 4011cb0ef41Sopenharmony_ci case CMD_BREAK: 4021cb0ef41Sopenharmony_ci PopContextToExpectedDepth(); 4031cb0ef41Sopenharmony_ci control_builder_->Break(); 4041cb0ef41Sopenharmony_ci return true; 4051cb0ef41Sopenharmony_ci case CMD_CONTINUE: 4061cb0ef41Sopenharmony_ci case CMD_RETURN: 4071cb0ef41Sopenharmony_ci case CMD_ASYNC_RETURN: 4081cb0ef41Sopenharmony_ci case CMD_RETHROW: 4091cb0ef41Sopenharmony_ci break; 4101cb0ef41Sopenharmony_ci } 4111cb0ef41Sopenharmony_ci return false; 4121cb0ef41Sopenharmony_ci } 4131cb0ef41Sopenharmony_ci 4141cb0ef41Sopenharmony_ci private: 4151cb0ef41Sopenharmony_ci Statement* statement_; 4161cb0ef41Sopenharmony_ci BreakableControlFlowBuilder* control_builder_; 4171cb0ef41Sopenharmony_ci}; 4181cb0ef41Sopenharmony_ci 4191cb0ef41Sopenharmony_ci// Scoped class for enabling 'break' and 'continue' in iteration 4201cb0ef41Sopenharmony_ci// constructs, e.g. do...while, while..., for... 4211cb0ef41Sopenharmony_ciclass BytecodeGenerator::ControlScopeForIteration final 4221cb0ef41Sopenharmony_ci : public BytecodeGenerator::ControlScope { 4231cb0ef41Sopenharmony_ci public: 4241cb0ef41Sopenharmony_ci ControlScopeForIteration(BytecodeGenerator* generator, 4251cb0ef41Sopenharmony_ci IterationStatement* statement, 4261cb0ef41Sopenharmony_ci LoopBuilder* loop_builder) 4271cb0ef41Sopenharmony_ci : ControlScope(generator), 4281cb0ef41Sopenharmony_ci statement_(statement), 4291cb0ef41Sopenharmony_ci loop_builder_(loop_builder) {} 4301cb0ef41Sopenharmony_ci 4311cb0ef41Sopenharmony_ci protected: 4321cb0ef41Sopenharmony_ci bool Execute(Command command, Statement* statement, 4331cb0ef41Sopenharmony_ci int source_position) override { 4341cb0ef41Sopenharmony_ci if (statement != statement_) return false; 4351cb0ef41Sopenharmony_ci switch (command) { 4361cb0ef41Sopenharmony_ci case CMD_BREAK: 4371cb0ef41Sopenharmony_ci PopContextToExpectedDepth(); 4381cb0ef41Sopenharmony_ci loop_builder_->Break(); 4391cb0ef41Sopenharmony_ci return true; 4401cb0ef41Sopenharmony_ci case CMD_CONTINUE: 4411cb0ef41Sopenharmony_ci PopContextToExpectedDepth(); 4421cb0ef41Sopenharmony_ci loop_builder_->Continue(); 4431cb0ef41Sopenharmony_ci return true; 4441cb0ef41Sopenharmony_ci case CMD_RETURN: 4451cb0ef41Sopenharmony_ci case CMD_ASYNC_RETURN: 4461cb0ef41Sopenharmony_ci case CMD_RETHROW: 4471cb0ef41Sopenharmony_ci break; 4481cb0ef41Sopenharmony_ci } 4491cb0ef41Sopenharmony_ci return false; 4501cb0ef41Sopenharmony_ci } 4511cb0ef41Sopenharmony_ci 4521cb0ef41Sopenharmony_ci private: 4531cb0ef41Sopenharmony_ci Statement* statement_; 4541cb0ef41Sopenharmony_ci LoopBuilder* loop_builder_; 4551cb0ef41Sopenharmony_ci}; 4561cb0ef41Sopenharmony_ci 4571cb0ef41Sopenharmony_ci// Scoped class for enabling 'throw' in try-catch constructs. 4581cb0ef41Sopenharmony_ciclass BytecodeGenerator::ControlScopeForTryCatch final 4591cb0ef41Sopenharmony_ci : public BytecodeGenerator::ControlScope { 4601cb0ef41Sopenharmony_ci public: 4611cb0ef41Sopenharmony_ci ControlScopeForTryCatch(BytecodeGenerator* generator, 4621cb0ef41Sopenharmony_ci TryCatchBuilder* try_catch_builder) 4631cb0ef41Sopenharmony_ci : ControlScope(generator) {} 4641cb0ef41Sopenharmony_ci 4651cb0ef41Sopenharmony_ci protected: 4661cb0ef41Sopenharmony_ci bool Execute(Command command, Statement* statement, 4671cb0ef41Sopenharmony_ci int source_position) override { 4681cb0ef41Sopenharmony_ci switch (command) { 4691cb0ef41Sopenharmony_ci case CMD_BREAK: 4701cb0ef41Sopenharmony_ci case CMD_CONTINUE: 4711cb0ef41Sopenharmony_ci case CMD_RETURN: 4721cb0ef41Sopenharmony_ci case CMD_ASYNC_RETURN: 4731cb0ef41Sopenharmony_ci break; 4741cb0ef41Sopenharmony_ci case CMD_RETHROW: 4751cb0ef41Sopenharmony_ci // No need to pop contexts, execution re-enters the method body via the 4761cb0ef41Sopenharmony_ci // stack unwinding mechanism which itself restores contexts correctly. 4771cb0ef41Sopenharmony_ci generator()->BuildReThrow(); 4781cb0ef41Sopenharmony_ci return true; 4791cb0ef41Sopenharmony_ci } 4801cb0ef41Sopenharmony_ci return false; 4811cb0ef41Sopenharmony_ci } 4821cb0ef41Sopenharmony_ci}; 4831cb0ef41Sopenharmony_ci 4841cb0ef41Sopenharmony_ci// Scoped class for enabling control flow through try-finally constructs. 4851cb0ef41Sopenharmony_ciclass BytecodeGenerator::ControlScopeForTryFinally final 4861cb0ef41Sopenharmony_ci : public BytecodeGenerator::ControlScope { 4871cb0ef41Sopenharmony_ci public: 4881cb0ef41Sopenharmony_ci ControlScopeForTryFinally(BytecodeGenerator* generator, 4891cb0ef41Sopenharmony_ci TryFinallyBuilder* try_finally_builder, 4901cb0ef41Sopenharmony_ci DeferredCommands* commands) 4911cb0ef41Sopenharmony_ci : ControlScope(generator), 4921cb0ef41Sopenharmony_ci try_finally_builder_(try_finally_builder), 4931cb0ef41Sopenharmony_ci commands_(commands) {} 4941cb0ef41Sopenharmony_ci 4951cb0ef41Sopenharmony_ci protected: 4961cb0ef41Sopenharmony_ci bool Execute(Command command, Statement* statement, 4971cb0ef41Sopenharmony_ci int source_position) override { 4981cb0ef41Sopenharmony_ci switch (command) { 4991cb0ef41Sopenharmony_ci case CMD_BREAK: 5001cb0ef41Sopenharmony_ci case CMD_CONTINUE: 5011cb0ef41Sopenharmony_ci case CMD_RETURN: 5021cb0ef41Sopenharmony_ci case CMD_ASYNC_RETURN: 5031cb0ef41Sopenharmony_ci case CMD_RETHROW: 5041cb0ef41Sopenharmony_ci PopContextToExpectedDepth(); 5051cb0ef41Sopenharmony_ci // We don't record source_position here since we don't generate return 5061cb0ef41Sopenharmony_ci // bytecode right here and will generate it later as part of finally 5071cb0ef41Sopenharmony_ci // block. Each return bytecode generated in finally block will get own 5081cb0ef41Sopenharmony_ci // return source position from corresponded return statement or we'll 5091cb0ef41Sopenharmony_ci // use end of function if no return statement is presented. 5101cb0ef41Sopenharmony_ci commands_->RecordCommand(command, statement); 5111cb0ef41Sopenharmony_ci try_finally_builder_->LeaveTry(); 5121cb0ef41Sopenharmony_ci return true; 5131cb0ef41Sopenharmony_ci } 5141cb0ef41Sopenharmony_ci return false; 5151cb0ef41Sopenharmony_ci } 5161cb0ef41Sopenharmony_ci 5171cb0ef41Sopenharmony_ci private: 5181cb0ef41Sopenharmony_ci TryFinallyBuilder* try_finally_builder_; 5191cb0ef41Sopenharmony_ci DeferredCommands* commands_; 5201cb0ef41Sopenharmony_ci}; 5211cb0ef41Sopenharmony_ci 5221cb0ef41Sopenharmony_ci// Allocate and fetch the coverage indices tracking NaryLogical Expressions. 5231cb0ef41Sopenharmony_ciclass BytecodeGenerator::NaryCodeCoverageSlots { 5241cb0ef41Sopenharmony_ci public: 5251cb0ef41Sopenharmony_ci NaryCodeCoverageSlots(BytecodeGenerator* generator, NaryOperation* expr) 5261cb0ef41Sopenharmony_ci : generator_(generator) { 5271cb0ef41Sopenharmony_ci if (generator_->block_coverage_builder_ == nullptr) return; 5281cb0ef41Sopenharmony_ci for (size_t i = 0; i < expr->subsequent_length(); i++) { 5291cb0ef41Sopenharmony_ci coverage_slots_.push_back( 5301cb0ef41Sopenharmony_ci generator_->AllocateNaryBlockCoverageSlotIfEnabled(expr, i)); 5311cb0ef41Sopenharmony_ci } 5321cb0ef41Sopenharmony_ci } 5331cb0ef41Sopenharmony_ci 5341cb0ef41Sopenharmony_ci int GetSlotFor(size_t subsequent_expr_index) const { 5351cb0ef41Sopenharmony_ci if (generator_->block_coverage_builder_ == nullptr) { 5361cb0ef41Sopenharmony_ci return BlockCoverageBuilder::kNoCoverageArraySlot; 5371cb0ef41Sopenharmony_ci } 5381cb0ef41Sopenharmony_ci DCHECK(coverage_slots_.size() > subsequent_expr_index); 5391cb0ef41Sopenharmony_ci return coverage_slots_[subsequent_expr_index]; 5401cb0ef41Sopenharmony_ci } 5411cb0ef41Sopenharmony_ci 5421cb0ef41Sopenharmony_ci private: 5431cb0ef41Sopenharmony_ci BytecodeGenerator* generator_; 5441cb0ef41Sopenharmony_ci std::vector<int> coverage_slots_; 5451cb0ef41Sopenharmony_ci}; 5461cb0ef41Sopenharmony_ci 5471cb0ef41Sopenharmony_civoid BytecodeGenerator::ControlScope::PerformCommand(Command command, 5481cb0ef41Sopenharmony_ci Statement* statement, 5491cb0ef41Sopenharmony_ci int source_position) { 5501cb0ef41Sopenharmony_ci ControlScope* current = this; 5511cb0ef41Sopenharmony_ci do { 5521cb0ef41Sopenharmony_ci if (current->Execute(command, statement, source_position)) { 5531cb0ef41Sopenharmony_ci return; 5541cb0ef41Sopenharmony_ci } 5551cb0ef41Sopenharmony_ci current = current->outer(); 5561cb0ef41Sopenharmony_ci } while (current != nullptr); 5571cb0ef41Sopenharmony_ci UNREACHABLE(); 5581cb0ef41Sopenharmony_ci} 5591cb0ef41Sopenharmony_ci 5601cb0ef41Sopenharmony_civoid BytecodeGenerator::ControlScope::PopContextToExpectedDepth() { 5611cb0ef41Sopenharmony_ci // Pop context to the expected depth. Note that this can in fact pop multiple 5621cb0ef41Sopenharmony_ci // contexts at once because the {PopContext} bytecode takes a saved register. 5631cb0ef41Sopenharmony_ci if (generator()->execution_context() != context()) { 5641cb0ef41Sopenharmony_ci generator()->builder()->PopContext(context()->reg()); 5651cb0ef41Sopenharmony_ci } 5661cb0ef41Sopenharmony_ci} 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::RegisterAllocationScope final { 5691cb0ef41Sopenharmony_ci public: 5701cb0ef41Sopenharmony_ci explicit RegisterAllocationScope(BytecodeGenerator* generator) 5711cb0ef41Sopenharmony_ci : generator_(generator), 5721cb0ef41Sopenharmony_ci outer_next_register_index_( 5731cb0ef41Sopenharmony_ci generator->register_allocator()->next_register_index()) {} 5741cb0ef41Sopenharmony_ci 5751cb0ef41Sopenharmony_ci ~RegisterAllocationScope() { 5761cb0ef41Sopenharmony_ci generator_->register_allocator()->ReleaseRegisters( 5771cb0ef41Sopenharmony_ci outer_next_register_index_); 5781cb0ef41Sopenharmony_ci } 5791cb0ef41Sopenharmony_ci 5801cb0ef41Sopenharmony_ci RegisterAllocationScope(const RegisterAllocationScope&) = delete; 5811cb0ef41Sopenharmony_ci RegisterAllocationScope& operator=(const RegisterAllocationScope&) = delete; 5821cb0ef41Sopenharmony_ci 5831cb0ef41Sopenharmony_ci BytecodeGenerator* generator() const { return generator_; } 5841cb0ef41Sopenharmony_ci 5851cb0ef41Sopenharmony_ci private: 5861cb0ef41Sopenharmony_ci BytecodeGenerator* generator_; 5871cb0ef41Sopenharmony_ci int outer_next_register_index_; 5881cb0ef41Sopenharmony_ci}; 5891cb0ef41Sopenharmony_ci 5901cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::AccumulatorPreservingScope final { 5911cb0ef41Sopenharmony_ci public: 5921cb0ef41Sopenharmony_ci explicit AccumulatorPreservingScope(BytecodeGenerator* generator, 5931cb0ef41Sopenharmony_ci AccumulatorPreservingMode mode) 5941cb0ef41Sopenharmony_ci : generator_(generator) { 5951cb0ef41Sopenharmony_ci if (mode == AccumulatorPreservingMode::kPreserve) { 5961cb0ef41Sopenharmony_ci saved_accumulator_register_ = 5971cb0ef41Sopenharmony_ci generator_->register_allocator()->NewRegister(); 5981cb0ef41Sopenharmony_ci generator_->builder()->StoreAccumulatorInRegister( 5991cb0ef41Sopenharmony_ci saved_accumulator_register_); 6001cb0ef41Sopenharmony_ci } 6011cb0ef41Sopenharmony_ci } 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_ci ~AccumulatorPreservingScope() { 6041cb0ef41Sopenharmony_ci if (saved_accumulator_register_.is_valid()) { 6051cb0ef41Sopenharmony_ci generator_->builder()->LoadAccumulatorWithRegister( 6061cb0ef41Sopenharmony_ci saved_accumulator_register_); 6071cb0ef41Sopenharmony_ci } 6081cb0ef41Sopenharmony_ci } 6091cb0ef41Sopenharmony_ci 6101cb0ef41Sopenharmony_ci AccumulatorPreservingScope(const AccumulatorPreservingScope&) = delete; 6111cb0ef41Sopenharmony_ci AccumulatorPreservingScope& operator=(const AccumulatorPreservingScope&) = 6121cb0ef41Sopenharmony_ci delete; 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ci private: 6151cb0ef41Sopenharmony_ci BytecodeGenerator* generator_; 6161cb0ef41Sopenharmony_ci Register saved_accumulator_register_; 6171cb0ef41Sopenharmony_ci}; 6181cb0ef41Sopenharmony_ci 6191cb0ef41Sopenharmony_ci// Scoped base class for determining how the result of an expression will be 6201cb0ef41Sopenharmony_ci// used. 6211cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::ExpressionResultScope { 6221cb0ef41Sopenharmony_ci public: 6231cb0ef41Sopenharmony_ci ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind) 6241cb0ef41Sopenharmony_ci : outer_(generator->execution_result()), 6251cb0ef41Sopenharmony_ci allocator_(generator), 6261cb0ef41Sopenharmony_ci kind_(kind), 6271cb0ef41Sopenharmony_ci type_hint_(TypeHint::kAny) { 6281cb0ef41Sopenharmony_ci generator->set_execution_result(this); 6291cb0ef41Sopenharmony_ci } 6301cb0ef41Sopenharmony_ci 6311cb0ef41Sopenharmony_ci ~ExpressionResultScope() { 6321cb0ef41Sopenharmony_ci allocator_.generator()->set_execution_result(outer_); 6331cb0ef41Sopenharmony_ci } 6341cb0ef41Sopenharmony_ci 6351cb0ef41Sopenharmony_ci ExpressionResultScope(const ExpressionResultScope&) = delete; 6361cb0ef41Sopenharmony_ci ExpressionResultScope& operator=(const ExpressionResultScope&) = delete; 6371cb0ef41Sopenharmony_ci 6381cb0ef41Sopenharmony_ci bool IsEffect() const { return kind_ == Expression::kEffect; } 6391cb0ef41Sopenharmony_ci bool IsValue() const { return kind_ == Expression::kValue; } 6401cb0ef41Sopenharmony_ci bool IsTest() const { return kind_ == Expression::kTest; } 6411cb0ef41Sopenharmony_ci 6421cb0ef41Sopenharmony_ci TestResultScope* AsTest() { 6431cb0ef41Sopenharmony_ci DCHECK(IsTest()); 6441cb0ef41Sopenharmony_ci return reinterpret_cast<TestResultScope*>(this); 6451cb0ef41Sopenharmony_ci } 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci // Specify expression always returns a Boolean result value. 6481cb0ef41Sopenharmony_ci void SetResultIsBoolean() { 6491cb0ef41Sopenharmony_ci DCHECK_EQ(type_hint_, TypeHint::kAny); 6501cb0ef41Sopenharmony_ci type_hint_ = TypeHint::kBoolean; 6511cb0ef41Sopenharmony_ci } 6521cb0ef41Sopenharmony_ci 6531cb0ef41Sopenharmony_ci void SetResultIsString() { 6541cb0ef41Sopenharmony_ci DCHECK_EQ(type_hint_, TypeHint::kAny); 6551cb0ef41Sopenharmony_ci type_hint_ = TypeHint::kString; 6561cb0ef41Sopenharmony_ci } 6571cb0ef41Sopenharmony_ci 6581cb0ef41Sopenharmony_ci TypeHint type_hint() const { return type_hint_; } 6591cb0ef41Sopenharmony_ci 6601cb0ef41Sopenharmony_ci private: 6611cb0ef41Sopenharmony_ci ExpressionResultScope* outer_; 6621cb0ef41Sopenharmony_ci RegisterAllocationScope allocator_; 6631cb0ef41Sopenharmony_ci Expression::Context kind_; 6641cb0ef41Sopenharmony_ci TypeHint type_hint_; 6651cb0ef41Sopenharmony_ci}; 6661cb0ef41Sopenharmony_ci 6671cb0ef41Sopenharmony_ci// Scoped class used when the result of the current expression is not 6681cb0ef41Sopenharmony_ci// expected to produce a result. 6691cb0ef41Sopenharmony_ciclass BytecodeGenerator::EffectResultScope final 6701cb0ef41Sopenharmony_ci : public ExpressionResultScope { 6711cb0ef41Sopenharmony_ci public: 6721cb0ef41Sopenharmony_ci explicit EffectResultScope(BytecodeGenerator* generator) 6731cb0ef41Sopenharmony_ci : ExpressionResultScope(generator, Expression::kEffect) {} 6741cb0ef41Sopenharmony_ci}; 6751cb0ef41Sopenharmony_ci 6761cb0ef41Sopenharmony_ci// Scoped class used when the result of the current expression to be 6771cb0ef41Sopenharmony_ci// evaluated should go into the interpreter's accumulator. 6781cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::ValueResultScope final 6791cb0ef41Sopenharmony_ci : public ExpressionResultScope { 6801cb0ef41Sopenharmony_ci public: 6811cb0ef41Sopenharmony_ci explicit ValueResultScope(BytecodeGenerator* generator) 6821cb0ef41Sopenharmony_ci : ExpressionResultScope(generator, Expression::kValue) {} 6831cb0ef41Sopenharmony_ci}; 6841cb0ef41Sopenharmony_ci 6851cb0ef41Sopenharmony_ci// Scoped class used when the result of the current expression to be 6861cb0ef41Sopenharmony_ci// evaluated is only tested with jumps to two branches. 6871cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::TestResultScope final 6881cb0ef41Sopenharmony_ci : public ExpressionResultScope { 6891cb0ef41Sopenharmony_ci public: 6901cb0ef41Sopenharmony_ci TestResultScope(BytecodeGenerator* generator, BytecodeLabels* then_labels, 6911cb0ef41Sopenharmony_ci BytecodeLabels* else_labels, TestFallthrough fallthrough) 6921cb0ef41Sopenharmony_ci : ExpressionResultScope(generator, Expression::kTest), 6931cb0ef41Sopenharmony_ci result_consumed_by_test_(false), 6941cb0ef41Sopenharmony_ci fallthrough_(fallthrough), 6951cb0ef41Sopenharmony_ci then_labels_(then_labels), 6961cb0ef41Sopenharmony_ci else_labels_(else_labels) {} 6971cb0ef41Sopenharmony_ci 6981cb0ef41Sopenharmony_ci TestResultScope(const TestResultScope&) = delete; 6991cb0ef41Sopenharmony_ci TestResultScope& operator=(const TestResultScope&) = delete; 7001cb0ef41Sopenharmony_ci 7011cb0ef41Sopenharmony_ci // Used when code special cases for TestResultScope and consumes any 7021cb0ef41Sopenharmony_ci // possible value by testing and jumping to a then/else label. 7031cb0ef41Sopenharmony_ci void SetResultConsumedByTest() { result_consumed_by_test_ = true; } 7041cb0ef41Sopenharmony_ci bool result_consumed_by_test() { return result_consumed_by_test_; } 7051cb0ef41Sopenharmony_ci 7061cb0ef41Sopenharmony_ci // Inverts the control flow of the operation, swapping the then and else 7071cb0ef41Sopenharmony_ci // labels and the fallthrough. 7081cb0ef41Sopenharmony_ci void InvertControlFlow() { 7091cb0ef41Sopenharmony_ci std::swap(then_labels_, else_labels_); 7101cb0ef41Sopenharmony_ci fallthrough_ = inverted_fallthrough(); 7111cb0ef41Sopenharmony_ci } 7121cb0ef41Sopenharmony_ci 7131cb0ef41Sopenharmony_ci BytecodeLabel* NewThenLabel() { return then_labels_->New(); } 7141cb0ef41Sopenharmony_ci BytecodeLabel* NewElseLabel() { return else_labels_->New(); } 7151cb0ef41Sopenharmony_ci 7161cb0ef41Sopenharmony_ci BytecodeLabels* then_labels() const { return then_labels_; } 7171cb0ef41Sopenharmony_ci BytecodeLabels* else_labels() const { return else_labels_; } 7181cb0ef41Sopenharmony_ci 7191cb0ef41Sopenharmony_ci void set_then_labels(BytecodeLabels* then_labels) { 7201cb0ef41Sopenharmony_ci then_labels_ = then_labels; 7211cb0ef41Sopenharmony_ci } 7221cb0ef41Sopenharmony_ci void set_else_labels(BytecodeLabels* else_labels) { 7231cb0ef41Sopenharmony_ci else_labels_ = else_labels; 7241cb0ef41Sopenharmony_ci } 7251cb0ef41Sopenharmony_ci 7261cb0ef41Sopenharmony_ci TestFallthrough fallthrough() const { return fallthrough_; } 7271cb0ef41Sopenharmony_ci TestFallthrough inverted_fallthrough() const { 7281cb0ef41Sopenharmony_ci switch (fallthrough_) { 7291cb0ef41Sopenharmony_ci case TestFallthrough::kThen: 7301cb0ef41Sopenharmony_ci return TestFallthrough::kElse; 7311cb0ef41Sopenharmony_ci case TestFallthrough::kElse: 7321cb0ef41Sopenharmony_ci return TestFallthrough::kThen; 7331cb0ef41Sopenharmony_ci default: 7341cb0ef41Sopenharmony_ci return TestFallthrough::kNone; 7351cb0ef41Sopenharmony_ci } 7361cb0ef41Sopenharmony_ci } 7371cb0ef41Sopenharmony_ci void set_fallthrough(TestFallthrough fallthrough) { 7381cb0ef41Sopenharmony_ci fallthrough_ = fallthrough; 7391cb0ef41Sopenharmony_ci } 7401cb0ef41Sopenharmony_ci 7411cb0ef41Sopenharmony_ci private: 7421cb0ef41Sopenharmony_ci bool result_consumed_by_test_; 7431cb0ef41Sopenharmony_ci TestFallthrough fallthrough_; 7441cb0ef41Sopenharmony_ci BytecodeLabels* then_labels_; 7451cb0ef41Sopenharmony_ci BytecodeLabels* else_labels_; 7461cb0ef41Sopenharmony_ci}; 7471cb0ef41Sopenharmony_ci 7481cb0ef41Sopenharmony_ci// Used to build a list of toplevel declaration data. 7491cb0ef41Sopenharmony_ciclass BytecodeGenerator::TopLevelDeclarationsBuilder final : public ZoneObject { 7501cb0ef41Sopenharmony_ci public: 7511cb0ef41Sopenharmony_ci template <typename IsolateT> 7521cb0ef41Sopenharmony_ci Handle<FixedArray> AllocateDeclarations(UnoptimizedCompilationInfo* info, 7531cb0ef41Sopenharmony_ci BytecodeGenerator* generator, 7541cb0ef41Sopenharmony_ci Handle<Script> script, 7551cb0ef41Sopenharmony_ci IsolateT* isolate) { 7561cb0ef41Sopenharmony_ci DCHECK(has_constant_pool_entry_); 7571cb0ef41Sopenharmony_ci 7581cb0ef41Sopenharmony_ci Handle<FixedArray> data = 7591cb0ef41Sopenharmony_ci isolate->factory()->NewFixedArray(entry_slots_, AllocationType::kOld); 7601cb0ef41Sopenharmony_ci 7611cb0ef41Sopenharmony_ci int array_index = 0; 7621cb0ef41Sopenharmony_ci if (info->scope()->is_module_scope()) { 7631cb0ef41Sopenharmony_ci for (Declaration* decl : *info->scope()->declarations()) { 7641cb0ef41Sopenharmony_ci Variable* var = decl->var(); 7651cb0ef41Sopenharmony_ci if (!var->is_used()) continue; 7661cb0ef41Sopenharmony_ci if (var->location() != VariableLocation::MODULE) continue; 7671cb0ef41Sopenharmony_ci#ifdef DEBUG 7681cb0ef41Sopenharmony_ci int start = array_index; 7691cb0ef41Sopenharmony_ci#endif 7701cb0ef41Sopenharmony_ci if (decl->IsFunctionDeclaration()) { 7711cb0ef41Sopenharmony_ci FunctionLiteral* f = static_cast<FunctionDeclaration*>(decl)->fun(); 7721cb0ef41Sopenharmony_ci Handle<SharedFunctionInfo> sfi( 7731cb0ef41Sopenharmony_ci Compiler::GetSharedFunctionInfo(f, script, isolate)); 7741cb0ef41Sopenharmony_ci // Return a null handle if any initial values can't be created. Caller 7751cb0ef41Sopenharmony_ci // will set stack overflow. 7761cb0ef41Sopenharmony_ci if (sfi.is_null()) return Handle<FixedArray>(); 7771cb0ef41Sopenharmony_ci data->set(array_index++, *sfi); 7781cb0ef41Sopenharmony_ci int literal_index = generator->GetCachedCreateClosureSlot(f); 7791cb0ef41Sopenharmony_ci data->set(array_index++, Smi::FromInt(literal_index)); 7801cb0ef41Sopenharmony_ci DCHECK(var->IsExport()); 7811cb0ef41Sopenharmony_ci data->set(array_index++, Smi::FromInt(var->index())); 7821cb0ef41Sopenharmony_ci DCHECK_EQ(start + kModuleFunctionDeclarationSize, array_index); 7831cb0ef41Sopenharmony_ci } else if (var->IsExport() && var->binding_needs_init()) { 7841cb0ef41Sopenharmony_ci data->set(array_index++, Smi::FromInt(var->index())); 7851cb0ef41Sopenharmony_ci DCHECK_EQ(start + kModuleVariableDeclarationSize, array_index); 7861cb0ef41Sopenharmony_ci } 7871cb0ef41Sopenharmony_ci } 7881cb0ef41Sopenharmony_ci } else { 7891cb0ef41Sopenharmony_ci for (Declaration* decl : *info->scope()->declarations()) { 7901cb0ef41Sopenharmony_ci Variable* var = decl->var(); 7911cb0ef41Sopenharmony_ci if (!var->is_used()) continue; 7921cb0ef41Sopenharmony_ci if (var->location() != VariableLocation::UNALLOCATED) continue; 7931cb0ef41Sopenharmony_ci#ifdef DEBUG 7941cb0ef41Sopenharmony_ci int start = array_index; 7951cb0ef41Sopenharmony_ci#endif 7961cb0ef41Sopenharmony_ci if (decl->IsVariableDeclaration()) { 7971cb0ef41Sopenharmony_ci data->set(array_index++, *var->raw_name()->string()); 7981cb0ef41Sopenharmony_ci DCHECK_EQ(start + kGlobalVariableDeclarationSize, array_index); 7991cb0ef41Sopenharmony_ci } else { 8001cb0ef41Sopenharmony_ci FunctionLiteral* f = static_cast<FunctionDeclaration*>(decl)->fun(); 8011cb0ef41Sopenharmony_ci Handle<SharedFunctionInfo> sfi( 8021cb0ef41Sopenharmony_ci Compiler::GetSharedFunctionInfo(f, script, isolate)); 8031cb0ef41Sopenharmony_ci // Return a null handle if any initial values can't be created. Caller 8041cb0ef41Sopenharmony_ci // will set stack overflow. 8051cb0ef41Sopenharmony_ci if (sfi.is_null()) return Handle<FixedArray>(); 8061cb0ef41Sopenharmony_ci data->set(array_index++, *sfi); 8071cb0ef41Sopenharmony_ci int literal_index = generator->GetCachedCreateClosureSlot(f); 8081cb0ef41Sopenharmony_ci data->set(array_index++, Smi::FromInt(literal_index)); 8091cb0ef41Sopenharmony_ci DCHECK_EQ(start + kGlobalFunctionDeclarationSize, array_index); 8101cb0ef41Sopenharmony_ci } 8111cb0ef41Sopenharmony_ci } 8121cb0ef41Sopenharmony_ci } 8131cb0ef41Sopenharmony_ci DCHECK_EQ(array_index, data->length()); 8141cb0ef41Sopenharmony_ci return data; 8151cb0ef41Sopenharmony_ci } 8161cb0ef41Sopenharmony_ci 8171cb0ef41Sopenharmony_ci size_t constant_pool_entry() { 8181cb0ef41Sopenharmony_ci DCHECK(has_constant_pool_entry_); 8191cb0ef41Sopenharmony_ci return constant_pool_entry_; 8201cb0ef41Sopenharmony_ci } 8211cb0ef41Sopenharmony_ci 8221cb0ef41Sopenharmony_ci void set_constant_pool_entry(size_t constant_pool_entry) { 8231cb0ef41Sopenharmony_ci DCHECK(has_top_level_declaration()); 8241cb0ef41Sopenharmony_ci DCHECK(!has_constant_pool_entry_); 8251cb0ef41Sopenharmony_ci constant_pool_entry_ = constant_pool_entry; 8261cb0ef41Sopenharmony_ci has_constant_pool_entry_ = true; 8271cb0ef41Sopenharmony_ci } 8281cb0ef41Sopenharmony_ci 8291cb0ef41Sopenharmony_ci void record_global_variable_declaration() { 8301cb0ef41Sopenharmony_ci entry_slots_ += kGlobalVariableDeclarationSize; 8311cb0ef41Sopenharmony_ci } 8321cb0ef41Sopenharmony_ci void record_global_function_declaration() { 8331cb0ef41Sopenharmony_ci entry_slots_ += kGlobalFunctionDeclarationSize; 8341cb0ef41Sopenharmony_ci } 8351cb0ef41Sopenharmony_ci void record_module_variable_declaration() { 8361cb0ef41Sopenharmony_ci entry_slots_ += kModuleVariableDeclarationSize; 8371cb0ef41Sopenharmony_ci } 8381cb0ef41Sopenharmony_ci void record_module_function_declaration() { 8391cb0ef41Sopenharmony_ci entry_slots_ += kModuleFunctionDeclarationSize; 8401cb0ef41Sopenharmony_ci } 8411cb0ef41Sopenharmony_ci bool has_top_level_declaration() { return entry_slots_ > 0; } 8421cb0ef41Sopenharmony_ci bool processed() { return processed_; } 8431cb0ef41Sopenharmony_ci void mark_processed() { processed_ = true; } 8441cb0ef41Sopenharmony_ci 8451cb0ef41Sopenharmony_ci private: 8461cb0ef41Sopenharmony_ci const int kGlobalVariableDeclarationSize = 1; 8471cb0ef41Sopenharmony_ci const int kGlobalFunctionDeclarationSize = 2; 8481cb0ef41Sopenharmony_ci const int kModuleVariableDeclarationSize = 1; 8491cb0ef41Sopenharmony_ci const int kModuleFunctionDeclarationSize = 3; 8501cb0ef41Sopenharmony_ci 8511cb0ef41Sopenharmony_ci size_t constant_pool_entry_ = 0; 8521cb0ef41Sopenharmony_ci int entry_slots_ = 0; 8531cb0ef41Sopenharmony_ci bool has_constant_pool_entry_ = false; 8541cb0ef41Sopenharmony_ci bool processed_ = false; 8551cb0ef41Sopenharmony_ci}; 8561cb0ef41Sopenharmony_ci 8571cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::CurrentScope final { 8581cb0ef41Sopenharmony_ci public: 8591cb0ef41Sopenharmony_ci CurrentScope(BytecodeGenerator* generator, Scope* scope) 8601cb0ef41Sopenharmony_ci : generator_(generator), outer_scope_(generator->current_scope()) { 8611cb0ef41Sopenharmony_ci if (scope != nullptr) { 8621cb0ef41Sopenharmony_ci DCHECK_EQ(outer_scope_, scope->outer_scope()); 8631cb0ef41Sopenharmony_ci generator_->set_current_scope(scope); 8641cb0ef41Sopenharmony_ci } 8651cb0ef41Sopenharmony_ci } 8661cb0ef41Sopenharmony_ci ~CurrentScope() { 8671cb0ef41Sopenharmony_ci if (outer_scope_ != generator_->current_scope()) { 8681cb0ef41Sopenharmony_ci generator_->set_current_scope(outer_scope_); 8691cb0ef41Sopenharmony_ci } 8701cb0ef41Sopenharmony_ci } 8711cb0ef41Sopenharmony_ci CurrentScope(const CurrentScope&) = delete; 8721cb0ef41Sopenharmony_ci CurrentScope& operator=(const CurrentScope&) = delete; 8731cb0ef41Sopenharmony_ci 8741cb0ef41Sopenharmony_ci private: 8751cb0ef41Sopenharmony_ci BytecodeGenerator* generator_; 8761cb0ef41Sopenharmony_ci Scope* outer_scope_; 8771cb0ef41Sopenharmony_ci}; 8781cb0ef41Sopenharmony_ci 8791cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::MultipleEntryBlockContextScope { 8801cb0ef41Sopenharmony_ci public: 8811cb0ef41Sopenharmony_ci MultipleEntryBlockContextScope(BytecodeGenerator* generator, Scope* scope) 8821cb0ef41Sopenharmony_ci : generator_(generator), scope_(scope), is_in_scope_(false) { 8831cb0ef41Sopenharmony_ci if (scope) { 8841cb0ef41Sopenharmony_ci inner_context_ = generator->register_allocator()->NewRegister(); 8851cb0ef41Sopenharmony_ci outer_context_ = generator->register_allocator()->NewRegister(); 8861cb0ef41Sopenharmony_ci generator->BuildNewLocalBlockContext(scope_); 8871cb0ef41Sopenharmony_ci generator->builder()->StoreAccumulatorInRegister(inner_context_); 8881cb0ef41Sopenharmony_ci } 8891cb0ef41Sopenharmony_ci } 8901cb0ef41Sopenharmony_ci 8911cb0ef41Sopenharmony_ci void SetEnteredIf(bool condition) { 8921cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(generator_); 8931cb0ef41Sopenharmony_ci if (condition && scope_ != nullptr && !is_in_scope_) { 8941cb0ef41Sopenharmony_ci EnterScope(); 8951cb0ef41Sopenharmony_ci } else if (!condition && is_in_scope_) { 8961cb0ef41Sopenharmony_ci ExitScope(); 8971cb0ef41Sopenharmony_ci } 8981cb0ef41Sopenharmony_ci } 8991cb0ef41Sopenharmony_ci 9001cb0ef41Sopenharmony_ci MultipleEntryBlockContextScope(const MultipleEntryBlockContextScope&) = 9011cb0ef41Sopenharmony_ci delete; 9021cb0ef41Sopenharmony_ci MultipleEntryBlockContextScope& operator=( 9031cb0ef41Sopenharmony_ci const MultipleEntryBlockContextScope&) = delete; 9041cb0ef41Sopenharmony_ci 9051cb0ef41Sopenharmony_ci private: 9061cb0ef41Sopenharmony_ci void EnterScope() { 9071cb0ef41Sopenharmony_ci DCHECK(inner_context_.is_valid()); 9081cb0ef41Sopenharmony_ci DCHECK(outer_context_.is_valid()); 9091cb0ef41Sopenharmony_ci DCHECK(!is_in_scope_); 9101cb0ef41Sopenharmony_ci Register temp = generator_->register_allocator()->NewRegister(); 9111cb0ef41Sopenharmony_ci generator_->builder()->StoreAccumulatorInRegister(temp); 9121cb0ef41Sopenharmony_ci generator_->builder()->LoadAccumulatorWithRegister(inner_context_); 9131cb0ef41Sopenharmony_ci current_scope_.emplace(generator_, scope_); 9141cb0ef41Sopenharmony_ci context_scope_.emplace(generator_, scope_, outer_context_); 9151cb0ef41Sopenharmony_ci generator_->builder()->LoadAccumulatorWithRegister(temp); 9161cb0ef41Sopenharmony_ci is_in_scope_ = true; 9171cb0ef41Sopenharmony_ci } 9181cb0ef41Sopenharmony_ci 9191cb0ef41Sopenharmony_ci void ExitScope() { 9201cb0ef41Sopenharmony_ci DCHECK(inner_context_.is_valid()); 9211cb0ef41Sopenharmony_ci DCHECK(outer_context_.is_valid()); 9221cb0ef41Sopenharmony_ci DCHECK(is_in_scope_); 9231cb0ef41Sopenharmony_ci Register temp = generator_->register_allocator()->NewRegister(); 9241cb0ef41Sopenharmony_ci generator_->builder()->StoreAccumulatorInRegister(temp); 9251cb0ef41Sopenharmony_ci context_scope_ = base::nullopt; 9261cb0ef41Sopenharmony_ci current_scope_ = base::nullopt; 9271cb0ef41Sopenharmony_ci generator_->builder()->LoadAccumulatorWithRegister(temp); 9281cb0ef41Sopenharmony_ci is_in_scope_ = false; 9291cb0ef41Sopenharmony_ci } 9301cb0ef41Sopenharmony_ci 9311cb0ef41Sopenharmony_ci BytecodeGenerator* generator_; 9321cb0ef41Sopenharmony_ci Scope* scope_; 9331cb0ef41Sopenharmony_ci Register inner_context_; 9341cb0ef41Sopenharmony_ci Register outer_context_; 9351cb0ef41Sopenharmony_ci bool is_in_scope_; 9361cb0ef41Sopenharmony_ci base::Optional<CurrentScope> current_scope_; 9371cb0ef41Sopenharmony_ci base::Optional<ContextScope> context_scope_; 9381cb0ef41Sopenharmony_ci}; 9391cb0ef41Sopenharmony_ci 9401cb0ef41Sopenharmony_ciclass BytecodeGenerator::FeedbackSlotCache : public ZoneObject { 9411cb0ef41Sopenharmony_ci public: 9421cb0ef41Sopenharmony_ci enum class SlotKind { 9431cb0ef41Sopenharmony_ci kStoreGlobalSloppy, 9441cb0ef41Sopenharmony_ci kStoreGlobalStrict, 9451cb0ef41Sopenharmony_ci kSetNamedStrict, 9461cb0ef41Sopenharmony_ci kSetNamedSloppy, 9471cb0ef41Sopenharmony_ci kLoadProperty, 9481cb0ef41Sopenharmony_ci kLoadSuperProperty, 9491cb0ef41Sopenharmony_ci kLoadGlobalNotInsideTypeof, 9501cb0ef41Sopenharmony_ci kLoadGlobalInsideTypeof, 9511cb0ef41Sopenharmony_ci kClosureFeedbackCell 9521cb0ef41Sopenharmony_ci }; 9531cb0ef41Sopenharmony_ci 9541cb0ef41Sopenharmony_ci explicit FeedbackSlotCache(Zone* zone) : map_(zone) {} 9551cb0ef41Sopenharmony_ci 9561cb0ef41Sopenharmony_ci void Put(SlotKind slot_kind, Variable* variable, int slot_index) { 9571cb0ef41Sopenharmony_ci PutImpl(slot_kind, 0, variable, slot_index); 9581cb0ef41Sopenharmony_ci } 9591cb0ef41Sopenharmony_ci void Put(SlotKind slot_kind, AstNode* node, int slot_index) { 9601cb0ef41Sopenharmony_ci PutImpl(slot_kind, 0, node, slot_index); 9611cb0ef41Sopenharmony_ci } 9621cb0ef41Sopenharmony_ci void Put(SlotKind slot_kind, int variable_index, const AstRawString* name, 9631cb0ef41Sopenharmony_ci int slot_index) { 9641cb0ef41Sopenharmony_ci PutImpl(slot_kind, variable_index, name, slot_index); 9651cb0ef41Sopenharmony_ci } 9661cb0ef41Sopenharmony_ci void Put(SlotKind slot_kind, const AstRawString* name, int slot_index) { 9671cb0ef41Sopenharmony_ci PutImpl(slot_kind, 0, name, slot_index); 9681cb0ef41Sopenharmony_ci } 9691cb0ef41Sopenharmony_ci 9701cb0ef41Sopenharmony_ci int Get(SlotKind slot_kind, Variable* variable) const { 9711cb0ef41Sopenharmony_ci return GetImpl(slot_kind, 0, variable); 9721cb0ef41Sopenharmony_ci } 9731cb0ef41Sopenharmony_ci int Get(SlotKind slot_kind, AstNode* node) const { 9741cb0ef41Sopenharmony_ci return GetImpl(slot_kind, 0, node); 9751cb0ef41Sopenharmony_ci } 9761cb0ef41Sopenharmony_ci int Get(SlotKind slot_kind, int variable_index, 9771cb0ef41Sopenharmony_ci const AstRawString* name) const { 9781cb0ef41Sopenharmony_ci return GetImpl(slot_kind, variable_index, name); 9791cb0ef41Sopenharmony_ci } 9801cb0ef41Sopenharmony_ci int Get(SlotKind slot_kind, const AstRawString* name) const { 9811cb0ef41Sopenharmony_ci return GetImpl(slot_kind, 0, name); 9821cb0ef41Sopenharmony_ci } 9831cb0ef41Sopenharmony_ci 9841cb0ef41Sopenharmony_ci private: 9851cb0ef41Sopenharmony_ci using Key = std::tuple<SlotKind, int, const void*>; 9861cb0ef41Sopenharmony_ci 9871cb0ef41Sopenharmony_ci void PutImpl(SlotKind slot_kind, int index, const void* node, 9881cb0ef41Sopenharmony_ci int slot_index) { 9891cb0ef41Sopenharmony_ci Key key = std::make_tuple(slot_kind, index, node); 9901cb0ef41Sopenharmony_ci auto entry = std::make_pair(key, slot_index); 9911cb0ef41Sopenharmony_ci map_.insert(entry); 9921cb0ef41Sopenharmony_ci } 9931cb0ef41Sopenharmony_ci 9941cb0ef41Sopenharmony_ci int GetImpl(SlotKind slot_kind, int index, const void* node) const { 9951cb0ef41Sopenharmony_ci Key key = std::make_tuple(slot_kind, index, node); 9961cb0ef41Sopenharmony_ci auto iter = map_.find(key); 9971cb0ef41Sopenharmony_ci if (iter != map_.end()) { 9981cb0ef41Sopenharmony_ci return iter->second; 9991cb0ef41Sopenharmony_ci } 10001cb0ef41Sopenharmony_ci return -1; 10011cb0ef41Sopenharmony_ci } 10021cb0ef41Sopenharmony_ci 10031cb0ef41Sopenharmony_ci ZoneMap<Key, int> map_; 10041cb0ef41Sopenharmony_ci}; 10051cb0ef41Sopenharmony_ci 10061cb0ef41Sopenharmony_ciclass BytecodeGenerator::IteratorRecord final { 10071cb0ef41Sopenharmony_ci public: 10081cb0ef41Sopenharmony_ci IteratorRecord(Register object_register, Register next_register, 10091cb0ef41Sopenharmony_ci IteratorType type = IteratorType::kNormal) 10101cb0ef41Sopenharmony_ci : type_(type), object_(object_register), next_(next_register) { 10111cb0ef41Sopenharmony_ci DCHECK(object_.is_valid() && next_.is_valid()); 10121cb0ef41Sopenharmony_ci } 10131cb0ef41Sopenharmony_ci 10141cb0ef41Sopenharmony_ci inline IteratorType type() const { return type_; } 10151cb0ef41Sopenharmony_ci inline Register object() const { return object_; } 10161cb0ef41Sopenharmony_ci inline Register next() const { return next_; } 10171cb0ef41Sopenharmony_ci 10181cb0ef41Sopenharmony_ci private: 10191cb0ef41Sopenharmony_ci IteratorType type_; 10201cb0ef41Sopenharmony_ci Register object_; 10211cb0ef41Sopenharmony_ci Register next_; 10221cb0ef41Sopenharmony_ci}; 10231cb0ef41Sopenharmony_ci 10241cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::OptionalChainNullLabelScope final { 10251cb0ef41Sopenharmony_ci public: 10261cb0ef41Sopenharmony_ci explicit OptionalChainNullLabelScope(BytecodeGenerator* bytecode_generator) 10271cb0ef41Sopenharmony_ci : bytecode_generator_(bytecode_generator), 10281cb0ef41Sopenharmony_ci labels_(bytecode_generator->zone()) { 10291cb0ef41Sopenharmony_ci prev_ = bytecode_generator_->optional_chaining_null_labels_; 10301cb0ef41Sopenharmony_ci bytecode_generator_->optional_chaining_null_labels_ = &labels_; 10311cb0ef41Sopenharmony_ci } 10321cb0ef41Sopenharmony_ci 10331cb0ef41Sopenharmony_ci ~OptionalChainNullLabelScope() { 10341cb0ef41Sopenharmony_ci bytecode_generator_->optional_chaining_null_labels_ = prev_; 10351cb0ef41Sopenharmony_ci } 10361cb0ef41Sopenharmony_ci 10371cb0ef41Sopenharmony_ci BytecodeLabels* labels() { return &labels_; } 10381cb0ef41Sopenharmony_ci 10391cb0ef41Sopenharmony_ci private: 10401cb0ef41Sopenharmony_ci BytecodeGenerator* bytecode_generator_; 10411cb0ef41Sopenharmony_ci BytecodeLabels labels_; 10421cb0ef41Sopenharmony_ci BytecodeLabels* prev_; 10431cb0ef41Sopenharmony_ci}; 10441cb0ef41Sopenharmony_ci 10451cb0ef41Sopenharmony_ci// LoopScope delimits the scope of {loop}, from its header to its final jump. 10461cb0ef41Sopenharmony_ci// It should be constructed iff a (conceptual) back edge should be produced. In 10471cb0ef41Sopenharmony_ci// the case of creating a LoopBuilder but never emitting the loop, it is valid 10481cb0ef41Sopenharmony_ci// to skip the creation of LoopScope. 10491cb0ef41Sopenharmony_ciclass V8_NODISCARD BytecodeGenerator::LoopScope final { 10501cb0ef41Sopenharmony_ci public: 10511cb0ef41Sopenharmony_ci explicit LoopScope(BytecodeGenerator* bytecode_generator, LoopBuilder* loop) 10521cb0ef41Sopenharmony_ci : bytecode_generator_(bytecode_generator), 10531cb0ef41Sopenharmony_ci parent_loop_scope_(bytecode_generator_->current_loop_scope()), 10541cb0ef41Sopenharmony_ci loop_builder_(loop) { 10551cb0ef41Sopenharmony_ci loop_builder_->LoopHeader(); 10561cb0ef41Sopenharmony_ci bytecode_generator_->set_current_loop_scope(this); 10571cb0ef41Sopenharmony_ci bytecode_generator_->loop_depth_++; 10581cb0ef41Sopenharmony_ci } 10591cb0ef41Sopenharmony_ci 10601cb0ef41Sopenharmony_ci ~LoopScope() { 10611cb0ef41Sopenharmony_ci bytecode_generator_->loop_depth_--; 10621cb0ef41Sopenharmony_ci bytecode_generator_->set_current_loop_scope(parent_loop_scope_); 10631cb0ef41Sopenharmony_ci DCHECK_GE(bytecode_generator_->loop_depth_, 0); 10641cb0ef41Sopenharmony_ci loop_builder_->JumpToHeader( 10651cb0ef41Sopenharmony_ci bytecode_generator_->loop_depth_, 10661cb0ef41Sopenharmony_ci parent_loop_scope_ ? parent_loop_scope_->loop_builder_ : nullptr); 10671cb0ef41Sopenharmony_ci } 10681cb0ef41Sopenharmony_ci 10691cb0ef41Sopenharmony_ci private: 10701cb0ef41Sopenharmony_ci BytecodeGenerator* const bytecode_generator_; 10711cb0ef41Sopenharmony_ci LoopScope* const parent_loop_scope_; 10721cb0ef41Sopenharmony_ci LoopBuilder* const loop_builder_; 10731cb0ef41Sopenharmony_ci}; 10741cb0ef41Sopenharmony_ci 10751cb0ef41Sopenharmony_cinamespace { 10761cb0ef41Sopenharmony_ci 10771cb0ef41Sopenharmony_citemplate <typename PropertyT> 10781cb0ef41Sopenharmony_cistruct Accessors : public ZoneObject { 10791cb0ef41Sopenharmony_ci Accessors() : getter(nullptr), setter(nullptr) {} 10801cb0ef41Sopenharmony_ci PropertyT* getter; 10811cb0ef41Sopenharmony_ci PropertyT* setter; 10821cb0ef41Sopenharmony_ci}; 10831cb0ef41Sopenharmony_ci 10841cb0ef41Sopenharmony_ci// A map from property names to getter/setter pairs allocated in the zone that 10851cb0ef41Sopenharmony_ci// also provides a way of accessing the pairs in the order they were first 10861cb0ef41Sopenharmony_ci// added so that the generated bytecode is always the same. 10871cb0ef41Sopenharmony_citemplate <typename PropertyT> 10881cb0ef41Sopenharmony_ciclass AccessorTable 10891cb0ef41Sopenharmony_ci : public base::TemplateHashMap<Literal, Accessors<PropertyT>, 10901cb0ef41Sopenharmony_ci bool (*)(void*, void*), 10911cb0ef41Sopenharmony_ci ZoneAllocationPolicy> { 10921cb0ef41Sopenharmony_ci public: 10931cb0ef41Sopenharmony_ci explicit AccessorTable(Zone* zone) 10941cb0ef41Sopenharmony_ci : base::TemplateHashMap<Literal, Accessors<PropertyT>, 10951cb0ef41Sopenharmony_ci bool (*)(void*, void*), ZoneAllocationPolicy>( 10961cb0ef41Sopenharmony_ci Literal::Match, ZoneAllocationPolicy(zone)), 10971cb0ef41Sopenharmony_ci zone_(zone) {} 10981cb0ef41Sopenharmony_ci 10991cb0ef41Sopenharmony_ci Accessors<PropertyT>* LookupOrInsert(Literal* key) { 11001cb0ef41Sopenharmony_ci auto it = this->find(key, true); 11011cb0ef41Sopenharmony_ci if (it->second == nullptr) { 11021cb0ef41Sopenharmony_ci it->second = zone_->New<Accessors<PropertyT>>(); 11031cb0ef41Sopenharmony_ci ordered_accessors_.push_back({key, it->second}); 11041cb0ef41Sopenharmony_ci } 11051cb0ef41Sopenharmony_ci return it->second; 11061cb0ef41Sopenharmony_ci } 11071cb0ef41Sopenharmony_ci 11081cb0ef41Sopenharmony_ci const std::vector<std::pair<Literal*, Accessors<PropertyT>*>>& 11091cb0ef41Sopenharmony_ci ordered_accessors() { 11101cb0ef41Sopenharmony_ci return ordered_accessors_; 11111cb0ef41Sopenharmony_ci } 11121cb0ef41Sopenharmony_ci 11131cb0ef41Sopenharmony_ci private: 11141cb0ef41Sopenharmony_ci std::vector<std::pair<Literal*, Accessors<PropertyT>*>> ordered_accessors_; 11151cb0ef41Sopenharmony_ci 11161cb0ef41Sopenharmony_ci Zone* zone_; 11171cb0ef41Sopenharmony_ci}; 11181cb0ef41Sopenharmony_ci 11191cb0ef41Sopenharmony_ci} // namespace 11201cb0ef41Sopenharmony_ci 11211cb0ef41Sopenharmony_ci#ifdef DEBUG 11221cb0ef41Sopenharmony_ci 11231cb0ef41Sopenharmony_cistatic bool IsInEagerLiterals( 11241cb0ef41Sopenharmony_ci FunctionLiteral* literal, 11251cb0ef41Sopenharmony_ci const std::vector<FunctionLiteral*>& eager_literals) { 11261cb0ef41Sopenharmony_ci for (FunctionLiteral* eager_literal : eager_literals) { 11271cb0ef41Sopenharmony_ci if (literal == eager_literal) return true; 11281cb0ef41Sopenharmony_ci } 11291cb0ef41Sopenharmony_ci return false; 11301cb0ef41Sopenharmony_ci} 11311cb0ef41Sopenharmony_ci 11321cb0ef41Sopenharmony_ci#endif // DEBUG 11331cb0ef41Sopenharmony_ci 11341cb0ef41Sopenharmony_ciBytecodeGenerator::BytecodeGenerator( 11351cb0ef41Sopenharmony_ci LocalIsolate* local_isolate, Zone* compile_zone, 11361cb0ef41Sopenharmony_ci UnoptimizedCompilationInfo* info, 11371cb0ef41Sopenharmony_ci const AstStringConstants* ast_string_constants, 11381cb0ef41Sopenharmony_ci std::vector<FunctionLiteral*>* eager_inner_literals, Handle<Script> script) 11391cb0ef41Sopenharmony_ci : local_isolate_(local_isolate), 11401cb0ef41Sopenharmony_ci zone_(compile_zone), 11411cb0ef41Sopenharmony_ci builder_(zone(), info->num_parameters_including_this(), 11421cb0ef41Sopenharmony_ci info->scope()->num_stack_slots(), info->feedback_vector_spec(), 11431cb0ef41Sopenharmony_ci info->SourcePositionRecordingMode()), 11441cb0ef41Sopenharmony_ci info_(info), 11451cb0ef41Sopenharmony_ci ast_string_constants_(ast_string_constants), 11461cb0ef41Sopenharmony_ci closure_scope_(info->scope()), 11471cb0ef41Sopenharmony_ci current_scope_(info->scope()), 11481cb0ef41Sopenharmony_ci eager_inner_literals_(eager_inner_literals), 11491cb0ef41Sopenharmony_ci script_(script), 11501cb0ef41Sopenharmony_ci feedback_slot_cache_(zone()->New<FeedbackSlotCache>(zone())), 11511cb0ef41Sopenharmony_ci top_level_builder_(zone()->New<TopLevelDeclarationsBuilder>()), 11521cb0ef41Sopenharmony_ci block_coverage_builder_(nullptr), 11531cb0ef41Sopenharmony_ci function_literals_(0, zone()), 11541cb0ef41Sopenharmony_ci native_function_literals_(0, zone()), 11551cb0ef41Sopenharmony_ci object_literals_(0, zone()), 11561cb0ef41Sopenharmony_ci array_literals_(0, zone()), 11571cb0ef41Sopenharmony_ci class_literals_(0, zone()), 11581cb0ef41Sopenharmony_ci template_objects_(0, zone()), 11591cb0ef41Sopenharmony_ci execution_control_(nullptr), 11601cb0ef41Sopenharmony_ci execution_context_(nullptr), 11611cb0ef41Sopenharmony_ci execution_result_(nullptr), 11621cb0ef41Sopenharmony_ci incoming_new_target_or_generator_(), 11631cb0ef41Sopenharmony_ci optional_chaining_null_labels_(nullptr), 11641cb0ef41Sopenharmony_ci dummy_feedback_slot_(feedback_spec(), FeedbackSlotKind::kCompareOp), 11651cb0ef41Sopenharmony_ci generator_jump_table_(nullptr), 11661cb0ef41Sopenharmony_ci suspend_count_(0), 11671cb0ef41Sopenharmony_ci loop_depth_(0), 11681cb0ef41Sopenharmony_ci current_loop_scope_(nullptr), 11691cb0ef41Sopenharmony_ci catch_prediction_(HandlerTable::UNCAUGHT) { 11701cb0ef41Sopenharmony_ci DCHECK_EQ(closure_scope(), closure_scope()->GetClosureScope()); 11711cb0ef41Sopenharmony_ci if (info->has_source_range_map()) { 11721cb0ef41Sopenharmony_ci block_coverage_builder_ = zone()->New<BlockCoverageBuilder>( 11731cb0ef41Sopenharmony_ci zone(), builder(), info->source_range_map()); 11741cb0ef41Sopenharmony_ci } 11751cb0ef41Sopenharmony_ci} 11761cb0ef41Sopenharmony_ci 11771cb0ef41Sopenharmony_cinamespace { 11781cb0ef41Sopenharmony_ci 11791cb0ef41Sopenharmony_citemplate <typename Isolate> 11801cb0ef41Sopenharmony_cistruct NullContextScopeHelper; 11811cb0ef41Sopenharmony_ci 11821cb0ef41Sopenharmony_citemplate <> 11831cb0ef41Sopenharmony_cistruct NullContextScopeHelper<Isolate> { 11841cb0ef41Sopenharmony_ci using Type = NullContextScope; 11851cb0ef41Sopenharmony_ci}; 11861cb0ef41Sopenharmony_ci 11871cb0ef41Sopenharmony_citemplate <> 11881cb0ef41Sopenharmony_cistruct NullContextScopeHelper<LocalIsolate> { 11891cb0ef41Sopenharmony_ci class V8_NODISCARD DummyNullContextScope { 11901cb0ef41Sopenharmony_ci public: 11911cb0ef41Sopenharmony_ci explicit DummyNullContextScope(LocalIsolate*) {} 11921cb0ef41Sopenharmony_ci }; 11931cb0ef41Sopenharmony_ci using Type = DummyNullContextScope; 11941cb0ef41Sopenharmony_ci}; 11951cb0ef41Sopenharmony_ci 11961cb0ef41Sopenharmony_citemplate <typename Isolate> 11971cb0ef41Sopenharmony_ciusing NullContextScopeFor = typename NullContextScopeHelper<Isolate>::Type; 11981cb0ef41Sopenharmony_ci 11991cb0ef41Sopenharmony_ci} // namespace 12001cb0ef41Sopenharmony_ci 12011cb0ef41Sopenharmony_citemplate <typename IsolateT> 12021cb0ef41Sopenharmony_ciHandle<BytecodeArray> BytecodeGenerator::FinalizeBytecode( 12031cb0ef41Sopenharmony_ci IsolateT* isolate, Handle<Script> script) { 12041cb0ef41Sopenharmony_ci DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); 12051cb0ef41Sopenharmony_ci#ifdef DEBUG 12061cb0ef41Sopenharmony_ci // Unoptimized compilation should be context-independent. Verify that we don't 12071cb0ef41Sopenharmony_ci // access the native context by nulling it out during finalization. 12081cb0ef41Sopenharmony_ci NullContextScopeFor<IsolateT> null_context_scope(isolate); 12091cb0ef41Sopenharmony_ci#endif 12101cb0ef41Sopenharmony_ci 12111cb0ef41Sopenharmony_ci AllocateDeferredConstants(isolate, script); 12121cb0ef41Sopenharmony_ci 12131cb0ef41Sopenharmony_ci if (block_coverage_builder_) { 12141cb0ef41Sopenharmony_ci Handle<CoverageInfo> coverage_info = 12151cb0ef41Sopenharmony_ci isolate->factory()->NewCoverageInfo(block_coverage_builder_->slots()); 12161cb0ef41Sopenharmony_ci info()->set_coverage_info(coverage_info); 12171cb0ef41Sopenharmony_ci if (FLAG_trace_block_coverage) { 12181cb0ef41Sopenharmony_ci StdoutStream os; 12191cb0ef41Sopenharmony_ci coverage_info->CoverageInfoPrint(os, info()->literal()->GetDebugName()); 12201cb0ef41Sopenharmony_ci } 12211cb0ef41Sopenharmony_ci } 12221cb0ef41Sopenharmony_ci 12231cb0ef41Sopenharmony_ci if (HasStackOverflow()) return Handle<BytecodeArray>(); 12241cb0ef41Sopenharmony_ci Handle<BytecodeArray> bytecode_array = builder()->ToBytecodeArray(isolate); 12251cb0ef41Sopenharmony_ci 12261cb0ef41Sopenharmony_ci if (incoming_new_target_or_generator_.is_valid()) { 12271cb0ef41Sopenharmony_ci bytecode_array->set_incoming_new_target_or_generator_register( 12281cb0ef41Sopenharmony_ci incoming_new_target_or_generator_); 12291cb0ef41Sopenharmony_ci } 12301cb0ef41Sopenharmony_ci 12311cb0ef41Sopenharmony_ci return bytecode_array; 12321cb0ef41Sopenharmony_ci} 12331cb0ef41Sopenharmony_ci 12341cb0ef41Sopenharmony_citemplate Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode( 12351cb0ef41Sopenharmony_ci Isolate* isolate, Handle<Script> script); 12361cb0ef41Sopenharmony_citemplate Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode( 12371cb0ef41Sopenharmony_ci LocalIsolate* isolate, Handle<Script> script); 12381cb0ef41Sopenharmony_ci 12391cb0ef41Sopenharmony_citemplate <typename IsolateT> 12401cb0ef41Sopenharmony_ciHandle<ByteArray> BytecodeGenerator::FinalizeSourcePositionTable( 12411cb0ef41Sopenharmony_ci IsolateT* isolate) { 12421cb0ef41Sopenharmony_ci DCHECK_EQ(ThreadId::Current(), isolate->thread_id()); 12431cb0ef41Sopenharmony_ci#ifdef DEBUG 12441cb0ef41Sopenharmony_ci // Unoptimized compilation should be context-independent. Verify that we don't 12451cb0ef41Sopenharmony_ci // access the native context by nulling it out during finalization. 12461cb0ef41Sopenharmony_ci NullContextScopeFor<IsolateT> null_context_scope(isolate); 12471cb0ef41Sopenharmony_ci#endif 12481cb0ef41Sopenharmony_ci 12491cb0ef41Sopenharmony_ci Handle<ByteArray> source_position_table = 12501cb0ef41Sopenharmony_ci builder()->ToSourcePositionTable(isolate); 12511cb0ef41Sopenharmony_ci 12521cb0ef41Sopenharmony_ci LOG_CODE_EVENT(isolate, 12531cb0ef41Sopenharmony_ci CodeLinePosInfoRecordEvent( 12541cb0ef41Sopenharmony_ci info_->bytecode_array()->GetFirstBytecodeAddress(), 12551cb0ef41Sopenharmony_ci *source_position_table, JitCodeEvent::BYTE_CODE)); 12561cb0ef41Sopenharmony_ci 12571cb0ef41Sopenharmony_ci return source_position_table; 12581cb0ef41Sopenharmony_ci} 12591cb0ef41Sopenharmony_ci 12601cb0ef41Sopenharmony_citemplate Handle<ByteArray> BytecodeGenerator::FinalizeSourcePositionTable( 12611cb0ef41Sopenharmony_ci Isolate* isolate); 12621cb0ef41Sopenharmony_citemplate Handle<ByteArray> BytecodeGenerator::FinalizeSourcePositionTable( 12631cb0ef41Sopenharmony_ci LocalIsolate* isolate); 12641cb0ef41Sopenharmony_ci 12651cb0ef41Sopenharmony_ci#ifdef DEBUG 12661cb0ef41Sopenharmony_ciint BytecodeGenerator::CheckBytecodeMatches(BytecodeArray bytecode) { 12671cb0ef41Sopenharmony_ci return builder()->CheckBytecodeMatches(bytecode); 12681cb0ef41Sopenharmony_ci} 12691cb0ef41Sopenharmony_ci#endif 12701cb0ef41Sopenharmony_ci 12711cb0ef41Sopenharmony_citemplate <typename IsolateT> 12721cb0ef41Sopenharmony_civoid BytecodeGenerator::AllocateDeferredConstants(IsolateT* isolate, 12731cb0ef41Sopenharmony_ci Handle<Script> script) { 12741cb0ef41Sopenharmony_ci if (top_level_builder()->has_top_level_declaration()) { 12751cb0ef41Sopenharmony_ci // Build global declaration pair array. 12761cb0ef41Sopenharmony_ci Handle<FixedArray> declarations = top_level_builder()->AllocateDeclarations( 12771cb0ef41Sopenharmony_ci info(), this, script, isolate); 12781cb0ef41Sopenharmony_ci if (declarations.is_null()) return SetStackOverflow(); 12791cb0ef41Sopenharmony_ci builder()->SetDeferredConstantPoolEntry( 12801cb0ef41Sopenharmony_ci top_level_builder()->constant_pool_entry(), declarations); 12811cb0ef41Sopenharmony_ci } 12821cb0ef41Sopenharmony_ci 12831cb0ef41Sopenharmony_ci // Find or build shared function infos. 12841cb0ef41Sopenharmony_ci for (std::pair<FunctionLiteral*, size_t> literal : function_literals_) { 12851cb0ef41Sopenharmony_ci FunctionLiteral* expr = literal.first; 12861cb0ef41Sopenharmony_ci Handle<SharedFunctionInfo> shared_info = 12871cb0ef41Sopenharmony_ci Compiler::GetSharedFunctionInfo(expr, script, isolate); 12881cb0ef41Sopenharmony_ci if (shared_info.is_null()) return SetStackOverflow(); 12891cb0ef41Sopenharmony_ci builder()->SetDeferredConstantPoolEntry(literal.second, shared_info); 12901cb0ef41Sopenharmony_ci } 12911cb0ef41Sopenharmony_ci 12921cb0ef41Sopenharmony_ci // Find or build shared function infos for the native function templates. 12931cb0ef41Sopenharmony_ci for (std::pair<NativeFunctionLiteral*, size_t> literal : 12941cb0ef41Sopenharmony_ci native_function_literals_) { 12951cb0ef41Sopenharmony_ci // This should only happen for main-thread compilations. 12961cb0ef41Sopenharmony_ci DCHECK((std::is_same<Isolate, v8::internal::Isolate>::value)); 12971cb0ef41Sopenharmony_ci 12981cb0ef41Sopenharmony_ci NativeFunctionLiteral* expr = literal.first; 12991cb0ef41Sopenharmony_ci v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 13001cb0ef41Sopenharmony_ci 13011cb0ef41Sopenharmony_ci // Compute the function template for the native function. 13021cb0ef41Sopenharmony_ci v8::Local<v8::FunctionTemplate> info = 13031cb0ef41Sopenharmony_ci expr->extension()->GetNativeFunctionTemplate( 13041cb0ef41Sopenharmony_ci v8_isolate, Utils::ToLocal(expr->name())); 13051cb0ef41Sopenharmony_ci DCHECK(!info.IsEmpty()); 13061cb0ef41Sopenharmony_ci 13071cb0ef41Sopenharmony_ci Handle<SharedFunctionInfo> shared_info = 13081cb0ef41Sopenharmony_ci FunctionTemplateInfo::GetOrCreateSharedFunctionInfo( 13091cb0ef41Sopenharmony_ci isolate, Utils::OpenHandle(*info), expr->name()); 13101cb0ef41Sopenharmony_ci DCHECK(!shared_info.is_null()); 13111cb0ef41Sopenharmony_ci builder()->SetDeferredConstantPoolEntry(literal.second, shared_info); 13121cb0ef41Sopenharmony_ci } 13131cb0ef41Sopenharmony_ci 13141cb0ef41Sopenharmony_ci // Build object literal constant properties 13151cb0ef41Sopenharmony_ci for (std::pair<ObjectLiteralBoilerplateBuilder*, size_t> literal : 13161cb0ef41Sopenharmony_ci object_literals_) { 13171cb0ef41Sopenharmony_ci ObjectLiteralBoilerplateBuilder* object_literal_builder = literal.first; 13181cb0ef41Sopenharmony_ci if (object_literal_builder->properties_count() > 0) { 13191cb0ef41Sopenharmony_ci // If constant properties is an empty fixed array, we've already added it 13201cb0ef41Sopenharmony_ci // to the constant pool when visiting the object literal. 13211cb0ef41Sopenharmony_ci Handle<ObjectBoilerplateDescription> constant_properties = 13221cb0ef41Sopenharmony_ci object_literal_builder->GetOrBuildBoilerplateDescription(isolate); 13231cb0ef41Sopenharmony_ci 13241cb0ef41Sopenharmony_ci builder()->SetDeferredConstantPoolEntry(literal.second, 13251cb0ef41Sopenharmony_ci constant_properties); 13261cb0ef41Sopenharmony_ci } 13271cb0ef41Sopenharmony_ci } 13281cb0ef41Sopenharmony_ci 13291cb0ef41Sopenharmony_ci // Build array literal constant elements 13301cb0ef41Sopenharmony_ci for (std::pair<ArrayLiteralBoilerplateBuilder*, size_t> literal : 13311cb0ef41Sopenharmony_ci array_literals_) { 13321cb0ef41Sopenharmony_ci ArrayLiteralBoilerplateBuilder* array_literal_builder = literal.first; 13331cb0ef41Sopenharmony_ci Handle<ArrayBoilerplateDescription> constant_elements = 13341cb0ef41Sopenharmony_ci array_literal_builder->GetOrBuildBoilerplateDescription(isolate); 13351cb0ef41Sopenharmony_ci builder()->SetDeferredConstantPoolEntry(literal.second, constant_elements); 13361cb0ef41Sopenharmony_ci } 13371cb0ef41Sopenharmony_ci 13381cb0ef41Sopenharmony_ci // Build class literal boilerplates. 13391cb0ef41Sopenharmony_ci for (std::pair<ClassLiteral*, size_t> literal : class_literals_) { 13401cb0ef41Sopenharmony_ci ClassLiteral* class_literal = literal.first; 13411cb0ef41Sopenharmony_ci Handle<ClassBoilerplate> class_boilerplate = 13421cb0ef41Sopenharmony_ci ClassBoilerplate::BuildClassBoilerplate(isolate, class_literal); 13431cb0ef41Sopenharmony_ci builder()->SetDeferredConstantPoolEntry(literal.second, class_boilerplate); 13441cb0ef41Sopenharmony_ci } 13451cb0ef41Sopenharmony_ci 13461cb0ef41Sopenharmony_ci // Build template literals. 13471cb0ef41Sopenharmony_ci for (std::pair<GetTemplateObject*, size_t> literal : template_objects_) { 13481cb0ef41Sopenharmony_ci GetTemplateObject* get_template_object = literal.first; 13491cb0ef41Sopenharmony_ci Handle<TemplateObjectDescription> description = 13501cb0ef41Sopenharmony_ci get_template_object->GetOrBuildDescription(isolate); 13511cb0ef41Sopenharmony_ci builder()->SetDeferredConstantPoolEntry(literal.second, description); 13521cb0ef41Sopenharmony_ci } 13531cb0ef41Sopenharmony_ci} 13541cb0ef41Sopenharmony_ci 13551cb0ef41Sopenharmony_citemplate void BytecodeGenerator::AllocateDeferredConstants( 13561cb0ef41Sopenharmony_ci Isolate* isolate, Handle<Script> script); 13571cb0ef41Sopenharmony_citemplate void BytecodeGenerator::AllocateDeferredConstants( 13581cb0ef41Sopenharmony_ci LocalIsolate* isolate, Handle<Script> script); 13591cb0ef41Sopenharmony_ci 13601cb0ef41Sopenharmony_cinamespace { 13611cb0ef41Sopenharmony_cibool NeedsContextInitialization(DeclarationScope* scope) { 13621cb0ef41Sopenharmony_ci return scope->NeedsContext() && !scope->is_script_scope() && 13631cb0ef41Sopenharmony_ci !scope->is_module_scope(); 13641cb0ef41Sopenharmony_ci} 13651cb0ef41Sopenharmony_ci} // namespace 13661cb0ef41Sopenharmony_ci 13671cb0ef41Sopenharmony_civoid BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) { 13681cb0ef41Sopenharmony_ci InitializeAstVisitor(stack_limit); 13691cb0ef41Sopenharmony_ci 13701cb0ef41Sopenharmony_ci // Initialize the incoming context. 13711cb0ef41Sopenharmony_ci ContextScope incoming_context(this, closure_scope()); 13721cb0ef41Sopenharmony_ci 13731cb0ef41Sopenharmony_ci // Initialize control scope. 13741cb0ef41Sopenharmony_ci ControlScopeForTopLevel control(this); 13751cb0ef41Sopenharmony_ci 13761cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 13771cb0ef41Sopenharmony_ci 13781cb0ef41Sopenharmony_ci AllocateTopLevelRegisters(); 13791cb0ef41Sopenharmony_ci 13801cb0ef41Sopenharmony_ci builder()->EmitFunctionStartSourcePosition( 13811cb0ef41Sopenharmony_ci info()->literal()->start_position()); 13821cb0ef41Sopenharmony_ci 13831cb0ef41Sopenharmony_ci if (info()->literal()->CanSuspend()) { 13841cb0ef41Sopenharmony_ci BuildGeneratorPrologue(); 13851cb0ef41Sopenharmony_ci } 13861cb0ef41Sopenharmony_ci 13871cb0ef41Sopenharmony_ci if (NeedsContextInitialization(closure_scope())) { 13881cb0ef41Sopenharmony_ci // Push a new inner context scope for the function. 13891cb0ef41Sopenharmony_ci BuildNewLocalActivationContext(); 13901cb0ef41Sopenharmony_ci ContextScope local_function_context(this, closure_scope()); 13911cb0ef41Sopenharmony_ci BuildLocalActivationContextInitialization(); 13921cb0ef41Sopenharmony_ci GenerateBytecodeBody(); 13931cb0ef41Sopenharmony_ci } else { 13941cb0ef41Sopenharmony_ci GenerateBytecodeBody(); 13951cb0ef41Sopenharmony_ci } 13961cb0ef41Sopenharmony_ci 13971cb0ef41Sopenharmony_ci // Check that we are not falling off the end. 13981cb0ef41Sopenharmony_ci DCHECK(builder()->RemainderOfBlockIsDead()); 13991cb0ef41Sopenharmony_ci} 14001cb0ef41Sopenharmony_ci 14011cb0ef41Sopenharmony_civoid BytecodeGenerator::GenerateBytecodeBody() { 14021cb0ef41Sopenharmony_ci // Build the arguments object if it is used. 14031cb0ef41Sopenharmony_ci VisitArgumentsObject(closure_scope()->arguments()); 14041cb0ef41Sopenharmony_ci 14051cb0ef41Sopenharmony_ci // Build rest arguments array if it is used. 14061cb0ef41Sopenharmony_ci Variable* rest_parameter = closure_scope()->rest_parameter(); 14071cb0ef41Sopenharmony_ci VisitRestArgumentsArray(rest_parameter); 14081cb0ef41Sopenharmony_ci 14091cb0ef41Sopenharmony_ci // Build assignment to the function name or {.this_function} 14101cb0ef41Sopenharmony_ci // variables if used. 14111cb0ef41Sopenharmony_ci VisitThisFunctionVariable(closure_scope()->function_var()); 14121cb0ef41Sopenharmony_ci VisitThisFunctionVariable(closure_scope()->this_function_var()); 14131cb0ef41Sopenharmony_ci 14141cb0ef41Sopenharmony_ci // Build assignment to {new.target} variable if it is used. 14151cb0ef41Sopenharmony_ci VisitNewTargetVariable(closure_scope()->new_target_var()); 14161cb0ef41Sopenharmony_ci 14171cb0ef41Sopenharmony_ci // Create a generator object if necessary and initialize the 14181cb0ef41Sopenharmony_ci // {.generator_object} variable. 14191cb0ef41Sopenharmony_ci FunctionLiteral* literal = info()->literal(); 14201cb0ef41Sopenharmony_ci if (IsResumableFunction(literal->kind())) { 14211cb0ef41Sopenharmony_ci BuildGeneratorObjectVariableInitialization(); 14221cb0ef41Sopenharmony_ci } 14231cb0ef41Sopenharmony_ci 14241cb0ef41Sopenharmony_ci // Emit tracing call if requested to do so. 14251cb0ef41Sopenharmony_ci if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter); 14261cb0ef41Sopenharmony_ci 14271cb0ef41Sopenharmony_ci // Emit type profile call. 14281cb0ef41Sopenharmony_ci if (info()->flags().collect_type_profile()) { 14291cb0ef41Sopenharmony_ci feedback_spec()->AddTypeProfileSlot(); 14301cb0ef41Sopenharmony_ci int num_parameters = closure_scope()->num_parameters(); 14311cb0ef41Sopenharmony_ci for (int i = 0; i < num_parameters; i++) { 14321cb0ef41Sopenharmony_ci Register parameter(builder()->Parameter(i)); 14331cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(parameter).CollectTypeProfile( 14341cb0ef41Sopenharmony_ci closure_scope()->parameter(i)->initializer_position()); 14351cb0ef41Sopenharmony_ci } 14361cb0ef41Sopenharmony_ci } 14371cb0ef41Sopenharmony_ci 14381cb0ef41Sopenharmony_ci // Increment the function-scope block coverage counter. 14391cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(literal, SourceRangeKind::kBody); 14401cb0ef41Sopenharmony_ci 14411cb0ef41Sopenharmony_ci // Visit declarations within the function scope. 14421cb0ef41Sopenharmony_ci if (closure_scope()->is_script_scope()) { 14431cb0ef41Sopenharmony_ci VisitGlobalDeclarations(closure_scope()->declarations()); 14441cb0ef41Sopenharmony_ci } else if (closure_scope()->is_module_scope()) { 14451cb0ef41Sopenharmony_ci VisitModuleDeclarations(closure_scope()->declarations()); 14461cb0ef41Sopenharmony_ci } else { 14471cb0ef41Sopenharmony_ci VisitDeclarations(closure_scope()->declarations()); 14481cb0ef41Sopenharmony_ci } 14491cb0ef41Sopenharmony_ci 14501cb0ef41Sopenharmony_ci // Emit initializing assignments for module namespace imports (if any). 14511cb0ef41Sopenharmony_ci VisitModuleNamespaceImports(); 14521cb0ef41Sopenharmony_ci 14531cb0ef41Sopenharmony_ci // The derived constructor case is handled in VisitCallSuper. 14541cb0ef41Sopenharmony_ci if (IsBaseConstructor(function_kind())) { 14551cb0ef41Sopenharmony_ci if (literal->class_scope_has_private_brand()) { 14561cb0ef41Sopenharmony_ci ClassScope* scope = info()->scope()->outer_scope()->AsClassScope(); 14571cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(scope->brand()); 14581cb0ef41Sopenharmony_ci BuildPrivateBrandInitialization(builder()->Receiver(), scope->brand()); 14591cb0ef41Sopenharmony_ci } 14601cb0ef41Sopenharmony_ci 14611cb0ef41Sopenharmony_ci if (literal->requires_instance_members_initializer()) { 14621cb0ef41Sopenharmony_ci BuildInstanceMemberInitialization(Register::function_closure(), 14631cb0ef41Sopenharmony_ci builder()->Receiver()); 14641cb0ef41Sopenharmony_ci } 14651cb0ef41Sopenharmony_ci } 14661cb0ef41Sopenharmony_ci 14671cb0ef41Sopenharmony_ci // Visit statements in the function body. 14681cb0ef41Sopenharmony_ci VisitStatements(literal->body()); 14691cb0ef41Sopenharmony_ci 14701cb0ef41Sopenharmony_ci // Emit an implicit return instruction in case control flow can fall off the 14711cb0ef41Sopenharmony_ci // end of the function without an explicit return being present on all paths. 14721cb0ef41Sopenharmony_ci if (!builder()->RemainderOfBlockIsDead()) { 14731cb0ef41Sopenharmony_ci builder()->LoadUndefined(); 14741cb0ef41Sopenharmony_ci BuildReturn(literal->return_position()); 14751cb0ef41Sopenharmony_ci } 14761cb0ef41Sopenharmony_ci} 14771cb0ef41Sopenharmony_ci 14781cb0ef41Sopenharmony_civoid BytecodeGenerator::AllocateTopLevelRegisters() { 14791cb0ef41Sopenharmony_ci if (IsResumableFunction(info()->literal()->kind())) { 14801cb0ef41Sopenharmony_ci // Either directly use generator_object_var or allocate a new register for 14811cb0ef41Sopenharmony_ci // the incoming generator object. 14821cb0ef41Sopenharmony_ci Variable* generator_object_var = closure_scope()->generator_object_var(); 14831cb0ef41Sopenharmony_ci if (generator_object_var->location() == VariableLocation::LOCAL) { 14841cb0ef41Sopenharmony_ci incoming_new_target_or_generator_ = 14851cb0ef41Sopenharmony_ci GetRegisterForLocalVariable(generator_object_var); 14861cb0ef41Sopenharmony_ci } else { 14871cb0ef41Sopenharmony_ci incoming_new_target_or_generator_ = register_allocator()->NewRegister(); 14881cb0ef41Sopenharmony_ci } 14891cb0ef41Sopenharmony_ci } else if (closure_scope()->new_target_var()) { 14901cb0ef41Sopenharmony_ci // Either directly use new_target_var or allocate a new register for 14911cb0ef41Sopenharmony_ci // the incoming new target object. 14921cb0ef41Sopenharmony_ci Variable* new_target_var = closure_scope()->new_target_var(); 14931cb0ef41Sopenharmony_ci if (new_target_var->location() == VariableLocation::LOCAL) { 14941cb0ef41Sopenharmony_ci incoming_new_target_or_generator_ = 14951cb0ef41Sopenharmony_ci GetRegisterForLocalVariable(new_target_var); 14961cb0ef41Sopenharmony_ci } else { 14971cb0ef41Sopenharmony_ci incoming_new_target_or_generator_ = register_allocator()->NewRegister(); 14981cb0ef41Sopenharmony_ci } 14991cb0ef41Sopenharmony_ci } 15001cb0ef41Sopenharmony_ci} 15011cb0ef41Sopenharmony_ci 15021cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildGeneratorPrologue() { 15031cb0ef41Sopenharmony_ci DCHECK_GT(info()->literal()->suspend_count(), 0); 15041cb0ef41Sopenharmony_ci DCHECK(generator_object().is_valid()); 15051cb0ef41Sopenharmony_ci generator_jump_table_ = 15061cb0ef41Sopenharmony_ci builder()->AllocateJumpTable(info()->literal()->suspend_count(), 0); 15071cb0ef41Sopenharmony_ci 15081cb0ef41Sopenharmony_ci // If the generator is not undefined, this is a resume, so perform state 15091cb0ef41Sopenharmony_ci // dispatch. 15101cb0ef41Sopenharmony_ci builder()->SwitchOnGeneratorState(generator_object(), generator_jump_table_); 15111cb0ef41Sopenharmony_ci 15121cb0ef41Sopenharmony_ci // Otherwise, fall-through to the ordinary function prologue, after which we 15131cb0ef41Sopenharmony_ci // will run into the generator object creation and other extra code inserted 15141cb0ef41Sopenharmony_ci // by the parser. 15151cb0ef41Sopenharmony_ci} 15161cb0ef41Sopenharmony_ci 15171cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitBlock(Block* stmt) { 15181cb0ef41Sopenharmony_ci // Visit declarations and statements. 15191cb0ef41Sopenharmony_ci CurrentScope current_scope(this, stmt->scope()); 15201cb0ef41Sopenharmony_ci if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { 15211cb0ef41Sopenharmony_ci BuildNewLocalBlockContext(stmt->scope()); 15221cb0ef41Sopenharmony_ci ContextScope scope(this, stmt->scope()); 15231cb0ef41Sopenharmony_ci VisitBlockDeclarationsAndStatements(stmt); 15241cb0ef41Sopenharmony_ci } else { 15251cb0ef41Sopenharmony_ci VisitBlockDeclarationsAndStatements(stmt); 15261cb0ef41Sopenharmony_ci } 15271cb0ef41Sopenharmony_ci} 15281cb0ef41Sopenharmony_ci 15291cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) { 15301cb0ef41Sopenharmony_ci BlockBuilder block_builder(builder(), block_coverage_builder_, stmt); 15311cb0ef41Sopenharmony_ci ControlScopeForBreakable execution_control(this, stmt, &block_builder); 15321cb0ef41Sopenharmony_ci if (stmt->scope() != nullptr) { 15331cb0ef41Sopenharmony_ci VisitDeclarations(stmt->scope()->declarations()); 15341cb0ef41Sopenharmony_ci } 15351cb0ef41Sopenharmony_ci VisitStatements(stmt->statements()); 15361cb0ef41Sopenharmony_ci} 15371cb0ef41Sopenharmony_ci 15381cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { 15391cb0ef41Sopenharmony_ci Variable* variable = decl->var(); 15401cb0ef41Sopenharmony_ci // Unused variables don't need to be visited. 15411cb0ef41Sopenharmony_ci if (!variable->is_used()) return; 15421cb0ef41Sopenharmony_ci 15431cb0ef41Sopenharmony_ci switch (variable->location()) { 15441cb0ef41Sopenharmony_ci case VariableLocation::UNALLOCATED: 15451cb0ef41Sopenharmony_ci case VariableLocation::MODULE: 15461cb0ef41Sopenharmony_ci UNREACHABLE(); 15471cb0ef41Sopenharmony_ci case VariableLocation::LOCAL: 15481cb0ef41Sopenharmony_ci if (variable->binding_needs_init()) { 15491cb0ef41Sopenharmony_ci Register destination(builder()->Local(variable->index())); 15501cb0ef41Sopenharmony_ci builder()->LoadTheHole().StoreAccumulatorInRegister(destination); 15511cb0ef41Sopenharmony_ci } 15521cb0ef41Sopenharmony_ci break; 15531cb0ef41Sopenharmony_ci case VariableLocation::PARAMETER: 15541cb0ef41Sopenharmony_ci if (variable->binding_needs_init()) { 15551cb0ef41Sopenharmony_ci Register destination(builder()->Parameter(variable->index())); 15561cb0ef41Sopenharmony_ci builder()->LoadTheHole().StoreAccumulatorInRegister(destination); 15571cb0ef41Sopenharmony_ci } 15581cb0ef41Sopenharmony_ci break; 15591cb0ef41Sopenharmony_ci case VariableLocation::REPL_GLOBAL: 15601cb0ef41Sopenharmony_ci // REPL let's are stored in script contexts. They get initialized 15611cb0ef41Sopenharmony_ci // with the hole the same way as normal context allocated variables. 15621cb0ef41Sopenharmony_ci case VariableLocation::CONTEXT: 15631cb0ef41Sopenharmony_ci if (variable->binding_needs_init()) { 15641cb0ef41Sopenharmony_ci DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope())); 15651cb0ef41Sopenharmony_ci builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(), 15661cb0ef41Sopenharmony_ci variable->index(), 0); 15671cb0ef41Sopenharmony_ci } 15681cb0ef41Sopenharmony_ci break; 15691cb0ef41Sopenharmony_ci case VariableLocation::LOOKUP: { 15701cb0ef41Sopenharmony_ci DCHECK_EQ(VariableMode::kDynamic, variable->mode()); 15711cb0ef41Sopenharmony_ci DCHECK(!variable->binding_needs_init()); 15721cb0ef41Sopenharmony_ci 15731cb0ef41Sopenharmony_ci Register name = register_allocator()->NewRegister(); 15741cb0ef41Sopenharmony_ci 15751cb0ef41Sopenharmony_ci builder() 15761cb0ef41Sopenharmony_ci ->LoadLiteral(variable->raw_name()) 15771cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(name) 15781cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kDeclareEvalVar, name); 15791cb0ef41Sopenharmony_ci break; 15801cb0ef41Sopenharmony_ci } 15811cb0ef41Sopenharmony_ci } 15821cb0ef41Sopenharmony_ci} 15831cb0ef41Sopenharmony_ci 15841cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { 15851cb0ef41Sopenharmony_ci Variable* variable = decl->var(); 15861cb0ef41Sopenharmony_ci DCHECK(variable->mode() == VariableMode::kLet || 15871cb0ef41Sopenharmony_ci variable->mode() == VariableMode::kVar || 15881cb0ef41Sopenharmony_ci variable->mode() == VariableMode::kDynamic); 15891cb0ef41Sopenharmony_ci // Unused variables don't need to be visited. 15901cb0ef41Sopenharmony_ci if (!variable->is_used()) return; 15911cb0ef41Sopenharmony_ci 15921cb0ef41Sopenharmony_ci switch (variable->location()) { 15931cb0ef41Sopenharmony_ci case VariableLocation::UNALLOCATED: 15941cb0ef41Sopenharmony_ci case VariableLocation::MODULE: 15951cb0ef41Sopenharmony_ci UNREACHABLE(); 15961cb0ef41Sopenharmony_ci case VariableLocation::PARAMETER: 15971cb0ef41Sopenharmony_ci case VariableLocation::LOCAL: { 15981cb0ef41Sopenharmony_ci VisitFunctionLiteral(decl->fun()); 15991cb0ef41Sopenharmony_ci BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided); 16001cb0ef41Sopenharmony_ci break; 16011cb0ef41Sopenharmony_ci } 16021cb0ef41Sopenharmony_ci case VariableLocation::REPL_GLOBAL: 16031cb0ef41Sopenharmony_ci case VariableLocation::CONTEXT: { 16041cb0ef41Sopenharmony_ci DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope())); 16051cb0ef41Sopenharmony_ci VisitFunctionLiteral(decl->fun()); 16061cb0ef41Sopenharmony_ci builder()->StoreContextSlot(execution_context()->reg(), variable->index(), 16071cb0ef41Sopenharmony_ci 0); 16081cb0ef41Sopenharmony_ci break; 16091cb0ef41Sopenharmony_ci } 16101cb0ef41Sopenharmony_ci case VariableLocation::LOOKUP: { 16111cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 16121cb0ef41Sopenharmony_ci builder() 16131cb0ef41Sopenharmony_ci ->LoadLiteral(variable->raw_name()) 16141cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[0]); 16151cb0ef41Sopenharmony_ci VisitFunctionLiteral(decl->fun()); 16161cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(args[1]).CallRuntime( 16171cb0ef41Sopenharmony_ci Runtime::kDeclareEvalFunction, args); 16181cb0ef41Sopenharmony_ci break; 16191cb0ef41Sopenharmony_ci } 16201cb0ef41Sopenharmony_ci } 16211cb0ef41Sopenharmony_ci DCHECK_IMPLIES( 16221cb0ef41Sopenharmony_ci eager_inner_literals_ != nullptr && decl->fun()->ShouldEagerCompile(), 16231cb0ef41Sopenharmony_ci IsInEagerLiterals(decl->fun(), *eager_inner_literals_)); 16241cb0ef41Sopenharmony_ci} 16251cb0ef41Sopenharmony_ci 16261cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitModuleNamespaceImports() { 16271cb0ef41Sopenharmony_ci if (!closure_scope()->is_module_scope()) return; 16281cb0ef41Sopenharmony_ci 16291cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 16301cb0ef41Sopenharmony_ci Register module_request = register_allocator()->NewRegister(); 16311cb0ef41Sopenharmony_ci 16321cb0ef41Sopenharmony_ci SourceTextModuleDescriptor* descriptor = 16331cb0ef41Sopenharmony_ci closure_scope()->AsModuleScope()->module(); 16341cb0ef41Sopenharmony_ci for (auto entry : descriptor->namespace_imports()) { 16351cb0ef41Sopenharmony_ci builder() 16361cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromInt(entry->module_request)) 16371cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(module_request) 16381cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kGetModuleNamespace, module_request); 16391cb0ef41Sopenharmony_ci Variable* var = closure_scope()->LookupInModule(entry->local_name); 16401cb0ef41Sopenharmony_ci BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided); 16411cb0ef41Sopenharmony_ci } 16421cb0ef41Sopenharmony_ci} 16431cb0ef41Sopenharmony_ci 16441cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildDeclareCall(Runtime::FunctionId id) { 16451cb0ef41Sopenharmony_ci if (!top_level_builder()->has_top_level_declaration()) return; 16461cb0ef41Sopenharmony_ci DCHECK(!top_level_builder()->processed()); 16471cb0ef41Sopenharmony_ci 16481cb0ef41Sopenharmony_ci top_level_builder()->set_constant_pool_entry( 16491cb0ef41Sopenharmony_ci builder()->AllocateDeferredConstantPoolEntry()); 16501cb0ef41Sopenharmony_ci 16511cb0ef41Sopenharmony_ci // Emit code to declare globals. 16521cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 16531cb0ef41Sopenharmony_ci builder() 16541cb0ef41Sopenharmony_ci ->LoadConstantPoolEntry(top_level_builder()->constant_pool_entry()) 16551cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[0]) 16561cb0ef41Sopenharmony_ci .MoveRegister(Register::function_closure(), args[1]) 16571cb0ef41Sopenharmony_ci .CallRuntime(id, args); 16581cb0ef41Sopenharmony_ci 16591cb0ef41Sopenharmony_ci top_level_builder()->mark_processed(); 16601cb0ef41Sopenharmony_ci} 16611cb0ef41Sopenharmony_ci 16621cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitModuleDeclarations(Declaration::List* decls) { 16631cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 16641cb0ef41Sopenharmony_ci for (Declaration* decl : *decls) { 16651cb0ef41Sopenharmony_ci Variable* var = decl->var(); 16661cb0ef41Sopenharmony_ci if (!var->is_used()) continue; 16671cb0ef41Sopenharmony_ci if (var->location() == VariableLocation::MODULE) { 16681cb0ef41Sopenharmony_ci if (decl->IsFunctionDeclaration()) { 16691cb0ef41Sopenharmony_ci DCHECK(var->IsExport()); 16701cb0ef41Sopenharmony_ci FunctionDeclaration* f = static_cast<FunctionDeclaration*>(decl); 16711cb0ef41Sopenharmony_ci AddToEagerLiteralsIfEager(f->fun()); 16721cb0ef41Sopenharmony_ci top_level_builder()->record_module_function_declaration(); 16731cb0ef41Sopenharmony_ci } else if (var->IsExport() && var->binding_needs_init()) { 16741cb0ef41Sopenharmony_ci DCHECK(decl->IsVariableDeclaration()); 16751cb0ef41Sopenharmony_ci top_level_builder()->record_module_variable_declaration(); 16761cb0ef41Sopenharmony_ci } 16771cb0ef41Sopenharmony_ci } else { 16781cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 16791cb0ef41Sopenharmony_ci Visit(decl); 16801cb0ef41Sopenharmony_ci } 16811cb0ef41Sopenharmony_ci } 16821cb0ef41Sopenharmony_ci BuildDeclareCall(Runtime::kDeclareModuleExports); 16831cb0ef41Sopenharmony_ci} 16841cb0ef41Sopenharmony_ci 16851cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitGlobalDeclarations(Declaration::List* decls) { 16861cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 16871cb0ef41Sopenharmony_ci for (Declaration* decl : *decls) { 16881cb0ef41Sopenharmony_ci Variable* var = decl->var(); 16891cb0ef41Sopenharmony_ci DCHECK(var->is_used()); 16901cb0ef41Sopenharmony_ci if (var->location() == VariableLocation::UNALLOCATED) { 16911cb0ef41Sopenharmony_ci // var or function. 16921cb0ef41Sopenharmony_ci if (decl->IsFunctionDeclaration()) { 16931cb0ef41Sopenharmony_ci top_level_builder()->record_global_function_declaration(); 16941cb0ef41Sopenharmony_ci FunctionDeclaration* f = static_cast<FunctionDeclaration*>(decl); 16951cb0ef41Sopenharmony_ci AddToEagerLiteralsIfEager(f->fun()); 16961cb0ef41Sopenharmony_ci } else { 16971cb0ef41Sopenharmony_ci top_level_builder()->record_global_variable_declaration(); 16981cb0ef41Sopenharmony_ci } 16991cb0ef41Sopenharmony_ci } else { 17001cb0ef41Sopenharmony_ci // let or const. Handled in NewScriptContext. 17011cb0ef41Sopenharmony_ci DCHECK(decl->IsVariableDeclaration()); 17021cb0ef41Sopenharmony_ci DCHECK(IsLexicalVariableMode(var->mode())); 17031cb0ef41Sopenharmony_ci } 17041cb0ef41Sopenharmony_ci } 17051cb0ef41Sopenharmony_ci 17061cb0ef41Sopenharmony_ci BuildDeclareCall(Runtime::kDeclareGlobals); 17071cb0ef41Sopenharmony_ci} 17081cb0ef41Sopenharmony_ci 17091cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) { 17101cb0ef41Sopenharmony_ci for (Declaration* decl : *declarations) { 17111cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 17121cb0ef41Sopenharmony_ci Visit(decl); 17131cb0ef41Sopenharmony_ci } 17141cb0ef41Sopenharmony_ci} 17151cb0ef41Sopenharmony_ci 17161cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitStatements( 17171cb0ef41Sopenharmony_ci const ZonePtrList<Statement>* statements) { 17181cb0ef41Sopenharmony_ci for (int i = 0; i < statements->length(); i++) { 17191cb0ef41Sopenharmony_ci // Allocate an outer register allocations scope for the statement. 17201cb0ef41Sopenharmony_ci RegisterAllocationScope allocation_scope(this); 17211cb0ef41Sopenharmony_ci Statement* stmt = statements->at(i); 17221cb0ef41Sopenharmony_ci Visit(stmt); 17231cb0ef41Sopenharmony_ci if (builder()->RemainderOfBlockIsDead()) break; 17241cb0ef41Sopenharmony_ci } 17251cb0ef41Sopenharmony_ci} 17261cb0ef41Sopenharmony_ci 17271cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { 17281cb0ef41Sopenharmony_ci builder()->SetStatementPosition(stmt); 17291cb0ef41Sopenharmony_ci VisitForEffect(stmt->expression()); 17301cb0ef41Sopenharmony_ci} 17311cb0ef41Sopenharmony_ci 17321cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {} 17331cb0ef41Sopenharmony_ci 17341cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { 17351cb0ef41Sopenharmony_ci ConditionalControlFlowBuilder conditional_builder( 17361cb0ef41Sopenharmony_ci builder(), block_coverage_builder_, stmt); 17371cb0ef41Sopenharmony_ci builder()->SetStatementPosition(stmt); 17381cb0ef41Sopenharmony_ci 17391cb0ef41Sopenharmony_ci if (stmt->condition()->ToBooleanIsTrue()) { 17401cb0ef41Sopenharmony_ci // Generate then block unconditionally as always true. 17411cb0ef41Sopenharmony_ci conditional_builder.Then(); 17421cb0ef41Sopenharmony_ci Visit(stmt->then_statement()); 17431cb0ef41Sopenharmony_ci } else if (stmt->condition()->ToBooleanIsFalse()) { 17441cb0ef41Sopenharmony_ci // Generate else block unconditionally if it exists. 17451cb0ef41Sopenharmony_ci if (stmt->HasElseStatement()) { 17461cb0ef41Sopenharmony_ci conditional_builder.Else(); 17471cb0ef41Sopenharmony_ci Visit(stmt->else_statement()); 17481cb0ef41Sopenharmony_ci } 17491cb0ef41Sopenharmony_ci } else { 17501cb0ef41Sopenharmony_ci // TODO(oth): If then statement is BreakStatement or 17511cb0ef41Sopenharmony_ci // ContinueStatement we can reduce number of generated 17521cb0ef41Sopenharmony_ci // jump/jump_ifs here. See BasicLoops test. 17531cb0ef41Sopenharmony_ci VisitForTest(stmt->condition(), conditional_builder.then_labels(), 17541cb0ef41Sopenharmony_ci conditional_builder.else_labels(), TestFallthrough::kThen); 17551cb0ef41Sopenharmony_ci 17561cb0ef41Sopenharmony_ci conditional_builder.Then(); 17571cb0ef41Sopenharmony_ci Visit(stmt->then_statement()); 17581cb0ef41Sopenharmony_ci 17591cb0ef41Sopenharmony_ci if (stmt->HasElseStatement()) { 17601cb0ef41Sopenharmony_ci conditional_builder.JumpToEnd(); 17611cb0ef41Sopenharmony_ci conditional_builder.Else(); 17621cb0ef41Sopenharmony_ci Visit(stmt->else_statement()); 17631cb0ef41Sopenharmony_ci } 17641cb0ef41Sopenharmony_ci } 17651cb0ef41Sopenharmony_ci} 17661cb0ef41Sopenharmony_ci 17671cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitSloppyBlockFunctionStatement( 17681cb0ef41Sopenharmony_ci SloppyBlockFunctionStatement* stmt) { 17691cb0ef41Sopenharmony_ci Visit(stmt->statement()); 17701cb0ef41Sopenharmony_ci} 17711cb0ef41Sopenharmony_ci 17721cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { 17731cb0ef41Sopenharmony_ci AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation); 17741cb0ef41Sopenharmony_ci builder()->SetStatementPosition(stmt); 17751cb0ef41Sopenharmony_ci execution_control()->Continue(stmt->target()); 17761cb0ef41Sopenharmony_ci} 17771cb0ef41Sopenharmony_ci 17781cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { 17791cb0ef41Sopenharmony_ci AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation); 17801cb0ef41Sopenharmony_ci builder()->SetStatementPosition(stmt); 17811cb0ef41Sopenharmony_ci execution_control()->Break(stmt->target()); 17821cb0ef41Sopenharmony_ci} 17831cb0ef41Sopenharmony_ci 17841cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { 17851cb0ef41Sopenharmony_ci AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation); 17861cb0ef41Sopenharmony_ci builder()->SetStatementPosition(stmt); 17871cb0ef41Sopenharmony_ci VisitForAccumulatorValue(stmt->expression()); 17881cb0ef41Sopenharmony_ci int return_position = stmt->end_position(); 17891cb0ef41Sopenharmony_ci if (return_position == ReturnStatement::kFunctionLiteralReturnPosition) { 17901cb0ef41Sopenharmony_ci return_position = info()->literal()->return_position(); 17911cb0ef41Sopenharmony_ci } 17921cb0ef41Sopenharmony_ci if (stmt->is_async_return()) { 17931cb0ef41Sopenharmony_ci execution_control()->AsyncReturnAccumulator(return_position); 17941cb0ef41Sopenharmony_ci } else { 17951cb0ef41Sopenharmony_ci execution_control()->ReturnAccumulator(return_position); 17961cb0ef41Sopenharmony_ci } 17971cb0ef41Sopenharmony_ci} 17981cb0ef41Sopenharmony_ci 17991cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { 18001cb0ef41Sopenharmony_ci builder()->SetStatementPosition(stmt); 18011cb0ef41Sopenharmony_ci VisitForAccumulatorValue(stmt->expression()); 18021cb0ef41Sopenharmony_ci BuildNewLocalWithContext(stmt->scope()); 18031cb0ef41Sopenharmony_ci VisitInScope(stmt->statement(), stmt->scope()); 18041cb0ef41Sopenharmony_ci} 18051cb0ef41Sopenharmony_ci 18061cb0ef41Sopenharmony_cinamespace { 18071cb0ef41Sopenharmony_ci 18081cb0ef41Sopenharmony_cibool IsSmiLiteralSwitchCaseValue(Expression* expr) { 18091cb0ef41Sopenharmony_ci if (expr->IsSmiLiteral() || 18101cb0ef41Sopenharmony_ci (expr->IsLiteral() && expr->AsLiteral()->IsNumber() && 18111cb0ef41Sopenharmony_ci expr->AsLiteral()->AsNumber() == 0.0)) { 18121cb0ef41Sopenharmony_ci return true; 18131cb0ef41Sopenharmony_ci#ifdef DEBUG 18141cb0ef41Sopenharmony_ci } else if (expr->IsLiteral() && expr->AsLiteral()->IsNumber()) { 18151cb0ef41Sopenharmony_ci DCHECK(!IsSmiDouble(expr->AsLiteral()->AsNumber())); 18161cb0ef41Sopenharmony_ci#endif 18171cb0ef41Sopenharmony_ci } 18181cb0ef41Sopenharmony_ci return false; 18191cb0ef41Sopenharmony_ci} 18201cb0ef41Sopenharmony_ci 18211cb0ef41Sopenharmony_ci// Precondition: we called IsSmiLiteral to check this. 18221cb0ef41Sopenharmony_ciinline int ReduceToSmiSwitchCaseValue(Expression* expr) { 18231cb0ef41Sopenharmony_ci if (V8_LIKELY(expr->IsSmiLiteral())) { 18241cb0ef41Sopenharmony_ci return expr->AsLiteral()->AsSmiLiteral().value(); 18251cb0ef41Sopenharmony_ci } else { 18261cb0ef41Sopenharmony_ci // Only the zero case is possible otherwise. 18271cb0ef41Sopenharmony_ci DCHECK(expr->IsLiteral() && expr->AsLiteral()->IsNumber() && 18281cb0ef41Sopenharmony_ci expr->AsLiteral()->AsNumber() == -0.0); 18291cb0ef41Sopenharmony_ci return 0; 18301cb0ef41Sopenharmony_ci } 18311cb0ef41Sopenharmony_ci} 18321cb0ef41Sopenharmony_ci 18331cb0ef41Sopenharmony_ci// Is the range of Smi's small enough relative to number of cases? 18341cb0ef41Sopenharmony_ciinline bool IsSpreadAcceptable(int spread, int ncases) { 18351cb0ef41Sopenharmony_ci return spread < FLAG_switch_table_spread_threshold * ncases; 18361cb0ef41Sopenharmony_ci} 18371cb0ef41Sopenharmony_ci 18381cb0ef41Sopenharmony_cistruct SwitchInfo { 18391cb0ef41Sopenharmony_ci static const int kDefaultNotFound = -1; 18401cb0ef41Sopenharmony_ci 18411cb0ef41Sopenharmony_ci std::map<int, CaseClause*> covered_cases; 18421cb0ef41Sopenharmony_ci int default_case; 18431cb0ef41Sopenharmony_ci 18441cb0ef41Sopenharmony_ci SwitchInfo() { default_case = kDefaultNotFound; } 18451cb0ef41Sopenharmony_ci 18461cb0ef41Sopenharmony_ci bool DefaultExists() { return default_case != kDefaultNotFound; } 18471cb0ef41Sopenharmony_ci bool CaseExists(int j) { 18481cb0ef41Sopenharmony_ci return covered_cases.find(j) != covered_cases.end(); 18491cb0ef41Sopenharmony_ci } 18501cb0ef41Sopenharmony_ci bool CaseExists(Expression* expr) { 18511cb0ef41Sopenharmony_ci return IsSmiLiteralSwitchCaseValue(expr) 18521cb0ef41Sopenharmony_ci ? CaseExists(ReduceToSmiSwitchCaseValue(expr)) 18531cb0ef41Sopenharmony_ci : false; 18541cb0ef41Sopenharmony_ci } 18551cb0ef41Sopenharmony_ci CaseClause* GetClause(int j) { return covered_cases[j]; } 18561cb0ef41Sopenharmony_ci 18571cb0ef41Sopenharmony_ci bool IsDuplicate(CaseClause* clause) { 18581cb0ef41Sopenharmony_ci return IsSmiLiteralSwitchCaseValue(clause->label()) && 18591cb0ef41Sopenharmony_ci CaseExists(clause->label()) && 18601cb0ef41Sopenharmony_ci clause != GetClause(ReduceToSmiSwitchCaseValue(clause->label())); 18611cb0ef41Sopenharmony_ci } 18621cb0ef41Sopenharmony_ci int MinCase() { 18631cb0ef41Sopenharmony_ci return covered_cases.size() == 0 ? INT_MAX : covered_cases.begin()->first; 18641cb0ef41Sopenharmony_ci } 18651cb0ef41Sopenharmony_ci int MaxCase() { 18661cb0ef41Sopenharmony_ci return covered_cases.size() == 0 ? INT_MIN : covered_cases.rbegin()->first; 18671cb0ef41Sopenharmony_ci } 18681cb0ef41Sopenharmony_ci void Print() { 18691cb0ef41Sopenharmony_ci std::cout << "Covered_cases: " << '\n'; 18701cb0ef41Sopenharmony_ci for (auto iter = covered_cases.begin(); iter != covered_cases.end(); 18711cb0ef41Sopenharmony_ci ++iter) { 18721cb0ef41Sopenharmony_ci std::cout << iter->first << "->" << iter->second << '\n'; 18731cb0ef41Sopenharmony_ci } 18741cb0ef41Sopenharmony_ci std::cout << "Default_case: " << default_case << '\n'; 18751cb0ef41Sopenharmony_ci } 18761cb0ef41Sopenharmony_ci}; 18771cb0ef41Sopenharmony_ci 18781cb0ef41Sopenharmony_ci// Checks whether we should use a jump table to implement a switch operation. 18791cb0ef41Sopenharmony_cibool IsSwitchOptimizable(SwitchStatement* stmt, SwitchInfo* info) { 18801cb0ef41Sopenharmony_ci ZonePtrList<CaseClause>* cases = stmt->cases(); 18811cb0ef41Sopenharmony_ci 18821cb0ef41Sopenharmony_ci for (int i = 0; i < cases->length(); ++i) { 18831cb0ef41Sopenharmony_ci CaseClause* clause = cases->at(i); 18841cb0ef41Sopenharmony_ci if (clause->is_default()) { 18851cb0ef41Sopenharmony_ci continue; 18861cb0ef41Sopenharmony_ci } else if (!(clause->label()->IsLiteral())) { 18871cb0ef41Sopenharmony_ci // Don't consider Smi cases after a non-literal, because we 18881cb0ef41Sopenharmony_ci // need to evaluate the non-literal. 18891cb0ef41Sopenharmony_ci break; 18901cb0ef41Sopenharmony_ci } else if (IsSmiLiteralSwitchCaseValue(clause->label())) { 18911cb0ef41Sopenharmony_ci int value = ReduceToSmiSwitchCaseValue(clause->label()); 18921cb0ef41Sopenharmony_ci info->covered_cases.insert({value, clause}); 18931cb0ef41Sopenharmony_ci } 18941cb0ef41Sopenharmony_ci } 18951cb0ef41Sopenharmony_ci 18961cb0ef41Sopenharmony_ci // GCC also jump-table optimizes switch statements with 6 cases or more. 18971cb0ef41Sopenharmony_ci if (static_cast<int>(info->covered_cases.size()) >= 18981cb0ef41Sopenharmony_ci FLAG_switch_table_min_cases) { 18991cb0ef41Sopenharmony_ci // Due to case spread will be used as the size of jump-table, 19001cb0ef41Sopenharmony_ci // we need to check if it doesn't overflow by casting its 19011cb0ef41Sopenharmony_ci // min and max bounds to int64_t, and calculate if the difference is less 19021cb0ef41Sopenharmony_ci // than or equal to INT_MAX. 19031cb0ef41Sopenharmony_ci int64_t min = static_cast<int64_t>(info->MinCase()); 19041cb0ef41Sopenharmony_ci int64_t max = static_cast<int64_t>(info->MaxCase()); 19051cb0ef41Sopenharmony_ci int64_t spread = max - min + 1; 19061cb0ef41Sopenharmony_ci 19071cb0ef41Sopenharmony_ci DCHECK_GT(spread, 0); 19081cb0ef41Sopenharmony_ci 19091cb0ef41Sopenharmony_ci // Check if casted spread is acceptable and doesn't overflow. 19101cb0ef41Sopenharmony_ci if (spread <= INT_MAX && 19111cb0ef41Sopenharmony_ci IsSpreadAcceptable(static_cast<int>(spread), cases->length())) { 19121cb0ef41Sopenharmony_ci return true; 19131cb0ef41Sopenharmony_ci } 19141cb0ef41Sopenharmony_ci } 19151cb0ef41Sopenharmony_ci // Invariant- covered_cases has all cases and only cases that will go in the 19161cb0ef41Sopenharmony_ci // jump table. 19171cb0ef41Sopenharmony_ci info->covered_cases.clear(); 19181cb0ef41Sopenharmony_ci return false; 19191cb0ef41Sopenharmony_ci} 19201cb0ef41Sopenharmony_ci 19211cb0ef41Sopenharmony_ci} // namespace 19221cb0ef41Sopenharmony_ci 19231cb0ef41Sopenharmony_ci// This adds a jump table optimization for switch statements with Smi cases. 19241cb0ef41Sopenharmony_ci// If there are 5+ non-duplicate Smi clauses, and they are sufficiently compact, 19251cb0ef41Sopenharmony_ci// we generate a jump table. In the fall-through path, we put the compare-jumps 19261cb0ef41Sopenharmony_ci// for the non-Smi cases. 19271cb0ef41Sopenharmony_ci 19281cb0ef41Sopenharmony_ci// e.g. 19291cb0ef41Sopenharmony_ci// 19301cb0ef41Sopenharmony_ci// switch(x){ 19311cb0ef41Sopenharmony_ci// case -0: out = 10; 19321cb0ef41Sopenharmony_ci// case 1: out = 11; break; 19331cb0ef41Sopenharmony_ci// case 0: out = 12; break; 19341cb0ef41Sopenharmony_ci// case 2: out = 13; 19351cb0ef41Sopenharmony_ci// case 3: out = 14; break; 19361cb0ef41Sopenharmony_ci// case 0.5: out = 15; break; 19371cb0ef41Sopenharmony_ci// case 4: out = 16; 19381cb0ef41Sopenharmony_ci// case y: out = 17; 19391cb0ef41Sopenharmony_ci// case 5: out = 18; 19401cb0ef41Sopenharmony_ci// default: out = 19; break; 19411cb0ef41Sopenharmony_ci// } 19421cb0ef41Sopenharmony_ci 19431cb0ef41Sopenharmony_ci// becomes this pseudo-bytecode: 19441cb0ef41Sopenharmony_ci 19451cb0ef41Sopenharmony_ci// lda x 19461cb0ef41Sopenharmony_ci// star r1 19471cb0ef41Sopenharmony_ci// test_type number 19481cb0ef41Sopenharmony_ci// jump_if_false @fallthrough 19491cb0ef41Sopenharmony_ci// ldar r1 19501cb0ef41Sopenharmony_ci// test_greater_than_or_equal_to smi_min 19511cb0ef41Sopenharmony_ci// jump_if_false @fallthrough 19521cb0ef41Sopenharmony_ci// ldar r1 19531cb0ef41Sopenharmony_ci// test_less_than_or_equal_to smi_max 19541cb0ef41Sopenharmony_ci// jump_if_false @fallthrough 19551cb0ef41Sopenharmony_ci// ldar r1 19561cb0ef41Sopenharmony_ci// bitwise_or 0 19571cb0ef41Sopenharmony_ci// star r2 19581cb0ef41Sopenharmony_ci// test_strict_equal r1 19591cb0ef41Sopenharmony_ci// jump_if_false @fallthrough 19601cb0ef41Sopenharmony_ci// ldar r2 19611cb0ef41Sopenharmony_ci// switch_on_smi {1: @case_1, 2: @case_2, 3: @case_3, 4: @case_4} 19621cb0ef41Sopenharmony_ci// @fallthrough: 19631cb0ef41Sopenharmony_ci// jump_if_strict_equal -0.0 @case_minus_0.0 19641cb0ef41Sopenharmony_ci// jump_if_strict_equal 0.5 @case_0.5 19651cb0ef41Sopenharmony_ci// jump_if_strict_equal y @case_y 19661cb0ef41Sopenharmony_ci// jump_if_strict_equal 5 @case_5 19671cb0ef41Sopenharmony_ci// jump @default 19681cb0ef41Sopenharmony_ci// @case_minus_0.0: 19691cb0ef41Sopenharmony_ci// <out = 10> 19701cb0ef41Sopenharmony_ci// @case_1 19711cb0ef41Sopenharmony_ci// <out = 11, break> 19721cb0ef41Sopenharmony_ci// @case_0: 19731cb0ef41Sopenharmony_ci// <out = 12, break> 19741cb0ef41Sopenharmony_ci// @case_2: 19751cb0ef41Sopenharmony_ci// <out = 13> 19761cb0ef41Sopenharmony_ci// @case_3: 19771cb0ef41Sopenharmony_ci// <out = 14, break> 19781cb0ef41Sopenharmony_ci// @case_0.5: 19791cb0ef41Sopenharmony_ci// <out = 15, break> 19801cb0ef41Sopenharmony_ci// @case_4: 19811cb0ef41Sopenharmony_ci// <out = 16> 19821cb0ef41Sopenharmony_ci// @case_y: 19831cb0ef41Sopenharmony_ci// <out = 17> 19841cb0ef41Sopenharmony_ci// @case_5: 19851cb0ef41Sopenharmony_ci// <out = 18> 19861cb0ef41Sopenharmony_ci// @default: 19871cb0ef41Sopenharmony_ci// <out = 19, break> 19881cb0ef41Sopenharmony_ci 19891cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 19901cb0ef41Sopenharmony_ci // We need this scope because we visit for register values. We have to 19911cb0ef41Sopenharmony_ci // maintain a execution result scope where registers can be allocated. 19921cb0ef41Sopenharmony_ci ZonePtrList<CaseClause>* clauses = stmt->cases(); 19931cb0ef41Sopenharmony_ci 19941cb0ef41Sopenharmony_ci SwitchInfo info; 19951cb0ef41Sopenharmony_ci BytecodeJumpTable* jump_table = nullptr; 19961cb0ef41Sopenharmony_ci bool use_jump_table = IsSwitchOptimizable(stmt, &info); 19971cb0ef41Sopenharmony_ci 19981cb0ef41Sopenharmony_ci // N_comp_cases is number of cases we will generate comparison jumps for. 19991cb0ef41Sopenharmony_ci // Note we ignore duplicate cases, since they are very unlikely. 20001cb0ef41Sopenharmony_ci 20011cb0ef41Sopenharmony_ci int n_comp_cases = clauses->length(); 20021cb0ef41Sopenharmony_ci if (use_jump_table) { 20031cb0ef41Sopenharmony_ci n_comp_cases -= static_cast<int>(info.covered_cases.size()); 20041cb0ef41Sopenharmony_ci jump_table = builder()->AllocateJumpTable( 20051cb0ef41Sopenharmony_ci info.MaxCase() - info.MinCase() + 1, info.MinCase()); 20061cb0ef41Sopenharmony_ci } 20071cb0ef41Sopenharmony_ci 20081cb0ef41Sopenharmony_ci // Are we still using any if-else bytecodes to evaluate the switch? 20091cb0ef41Sopenharmony_ci bool use_jumps = n_comp_cases != 0; 20101cb0ef41Sopenharmony_ci 20111cb0ef41Sopenharmony_ci SwitchBuilder switch_builder(builder(), block_coverage_builder_, stmt, 20121cb0ef41Sopenharmony_ci n_comp_cases, jump_table); 20131cb0ef41Sopenharmony_ci ControlScopeForBreakable scope(this, stmt, &switch_builder); 20141cb0ef41Sopenharmony_ci builder()->SetStatementPosition(stmt); 20151cb0ef41Sopenharmony_ci 20161cb0ef41Sopenharmony_ci VisitForAccumulatorValue(stmt->tag()); 20171cb0ef41Sopenharmony_ci 20181cb0ef41Sopenharmony_ci if (use_jump_table) { 20191cb0ef41Sopenharmony_ci // This also fills empty slots in jump table. 20201cb0ef41Sopenharmony_ci Register r2 = register_allocator()->NewRegister(); 20211cb0ef41Sopenharmony_ci 20221cb0ef41Sopenharmony_ci Register r1 = register_allocator()->NewRegister(); 20231cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(r1); 20241cb0ef41Sopenharmony_ci 20251cb0ef41Sopenharmony_ci builder()->CompareTypeOf(TestTypeOfFlags::LiteralFlag::kNumber); 20261cb0ef41Sopenharmony_ci switch_builder.JumpToFallThroughIfFalse(); 20271cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(r1); 20281cb0ef41Sopenharmony_ci 20291cb0ef41Sopenharmony_ci // TODO(leszeks): Note these are duplicated range checks with the 20301cb0ef41Sopenharmony_ci // SwitchOnSmi handler for the most part. 20311cb0ef41Sopenharmony_ci 20321cb0ef41Sopenharmony_ci builder()->LoadLiteral(Smi::kMinValue); 20331cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(r2); 20341cb0ef41Sopenharmony_ci builder()->CompareOperation( 20351cb0ef41Sopenharmony_ci Token::Value::GTE, r1, 20361cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCompareICSlot())); 20371cb0ef41Sopenharmony_ci 20381cb0ef41Sopenharmony_ci switch_builder.JumpToFallThroughIfFalse(); 20391cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(r1); 20401cb0ef41Sopenharmony_ci 20411cb0ef41Sopenharmony_ci builder()->LoadLiteral(Smi::kMaxValue); 20421cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(r2); 20431cb0ef41Sopenharmony_ci builder()->CompareOperation( 20441cb0ef41Sopenharmony_ci Token::Value::LTE, r1, 20451cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCompareICSlot())); 20461cb0ef41Sopenharmony_ci 20471cb0ef41Sopenharmony_ci switch_builder.JumpToFallThroughIfFalse(); 20481cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(r1); 20491cb0ef41Sopenharmony_ci 20501cb0ef41Sopenharmony_ci builder()->BinaryOperationSmiLiteral( 20511cb0ef41Sopenharmony_ci Token::Value::BIT_OR, Smi::FromInt(0), 20521cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddBinaryOpICSlot())); 20531cb0ef41Sopenharmony_ci 20541cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(r2); 20551cb0ef41Sopenharmony_ci builder()->CompareOperation( 20561cb0ef41Sopenharmony_ci Token::Value::EQ_STRICT, r1, 20571cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCompareICSlot())); 20581cb0ef41Sopenharmony_ci 20591cb0ef41Sopenharmony_ci switch_builder.JumpToFallThroughIfFalse(); 20601cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(r2); 20611cb0ef41Sopenharmony_ci 20621cb0ef41Sopenharmony_ci switch_builder.EmitJumpTableIfExists(info.MinCase(), info.MaxCase(), 20631cb0ef41Sopenharmony_ci info.covered_cases); 20641cb0ef41Sopenharmony_ci 20651cb0ef41Sopenharmony_ci if (use_jumps) { 20661cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(r1); 20671cb0ef41Sopenharmony_ci } 20681cb0ef41Sopenharmony_ci } 20691cb0ef41Sopenharmony_ci 20701cb0ef41Sopenharmony_ci int case_compare_ctr = 0; 20711cb0ef41Sopenharmony_ci#ifdef DEBUG 20721cb0ef41Sopenharmony_ci std::unordered_map<int, int> case_ctr_checker; 20731cb0ef41Sopenharmony_ci#endif 20741cb0ef41Sopenharmony_ci 20751cb0ef41Sopenharmony_ci if (use_jumps) { 20761cb0ef41Sopenharmony_ci Register tag_holder = register_allocator()->NewRegister(); 20771cb0ef41Sopenharmony_ci FeedbackSlot slot = clauses->length() > 0 20781cb0ef41Sopenharmony_ci ? feedback_spec()->AddCompareICSlot() 20791cb0ef41Sopenharmony_ci : FeedbackSlot::Invalid(); 20801cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(tag_holder); 20811cb0ef41Sopenharmony_ci 20821cb0ef41Sopenharmony_ci for (int i = 0; i < clauses->length(); ++i) { 20831cb0ef41Sopenharmony_ci CaseClause* clause = clauses->at(i); 20841cb0ef41Sopenharmony_ci if (clause->is_default()) { 20851cb0ef41Sopenharmony_ci info.default_case = i; 20861cb0ef41Sopenharmony_ci } else if (!info.CaseExists(clause->label())) { 20871cb0ef41Sopenharmony_ci // Perform label comparison as if via '===' with tag. 20881cb0ef41Sopenharmony_ci VisitForAccumulatorValue(clause->label()); 20891cb0ef41Sopenharmony_ci builder()->CompareOperation(Token::Value::EQ_STRICT, tag_holder, 20901cb0ef41Sopenharmony_ci feedback_index(slot)); 20911cb0ef41Sopenharmony_ci#ifdef DEBUG 20921cb0ef41Sopenharmony_ci case_ctr_checker[i] = case_compare_ctr; 20931cb0ef41Sopenharmony_ci#endif 20941cb0ef41Sopenharmony_ci switch_builder.JumpToCaseIfTrue(ToBooleanMode::kAlreadyBoolean, 20951cb0ef41Sopenharmony_ci case_compare_ctr++); 20961cb0ef41Sopenharmony_ci } 20971cb0ef41Sopenharmony_ci } 20981cb0ef41Sopenharmony_ci } 20991cb0ef41Sopenharmony_ci 21001cb0ef41Sopenharmony_ci // For fall-throughs after comparisons (or out-of-range/non-Smi's for jump 21011cb0ef41Sopenharmony_ci // tables). 21021cb0ef41Sopenharmony_ci if (info.DefaultExists()) { 21031cb0ef41Sopenharmony_ci switch_builder.JumpToDefault(); 21041cb0ef41Sopenharmony_ci } else { 21051cb0ef41Sopenharmony_ci switch_builder.Break(); 21061cb0ef41Sopenharmony_ci } 21071cb0ef41Sopenharmony_ci 21081cb0ef41Sopenharmony_ci case_compare_ctr = 0; 21091cb0ef41Sopenharmony_ci for (int i = 0; i < clauses->length(); ++i) { 21101cb0ef41Sopenharmony_ci CaseClause* clause = clauses->at(i); 21111cb0ef41Sopenharmony_ci if (i != info.default_case) { 21121cb0ef41Sopenharmony_ci if (!info.IsDuplicate(clause)) { 21131cb0ef41Sopenharmony_ci bool use_table = use_jump_table && info.CaseExists(clause->label()); 21141cb0ef41Sopenharmony_ci if (!use_table) { 21151cb0ef41Sopenharmony_ci// Guarantee that we should generate compare/jump if no table. 21161cb0ef41Sopenharmony_ci#ifdef DEBUG 21171cb0ef41Sopenharmony_ci DCHECK(case_ctr_checker[i] == case_compare_ctr); 21181cb0ef41Sopenharmony_ci#endif 21191cb0ef41Sopenharmony_ci switch_builder.BindCaseTargetForCompareJump(case_compare_ctr++, 21201cb0ef41Sopenharmony_ci clause); 21211cb0ef41Sopenharmony_ci } else { 21221cb0ef41Sopenharmony_ci // Use jump table if this is not a duplicate label. 21231cb0ef41Sopenharmony_ci switch_builder.BindCaseTargetForJumpTable( 21241cb0ef41Sopenharmony_ci ReduceToSmiSwitchCaseValue(clause->label()), clause); 21251cb0ef41Sopenharmony_ci } 21261cb0ef41Sopenharmony_ci } 21271cb0ef41Sopenharmony_ci } else { 21281cb0ef41Sopenharmony_ci switch_builder.BindDefault(clause); 21291cb0ef41Sopenharmony_ci } 21301cb0ef41Sopenharmony_ci // Regardless, generate code (in case of fall throughs). 21311cb0ef41Sopenharmony_ci VisitStatements(clause->statements()); 21321cb0ef41Sopenharmony_ci } 21331cb0ef41Sopenharmony_ci} 21341cb0ef41Sopenharmony_ci 21351cb0ef41Sopenharmony_citemplate <typename TryBodyFunc, typename CatchBodyFunc> 21361cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildTryCatch( 21371cb0ef41Sopenharmony_ci TryBodyFunc try_body_func, CatchBodyFunc catch_body_func, 21381cb0ef41Sopenharmony_ci HandlerTable::CatchPrediction catch_prediction, 21391cb0ef41Sopenharmony_ci TryCatchStatement* stmt_for_coverage) { 21401cb0ef41Sopenharmony_ci if (builder()->RemainderOfBlockIsDead()) return; 21411cb0ef41Sopenharmony_ci 21421cb0ef41Sopenharmony_ci TryCatchBuilder try_control_builder( 21431cb0ef41Sopenharmony_ci builder(), 21441cb0ef41Sopenharmony_ci stmt_for_coverage == nullptr ? nullptr : block_coverage_builder_, 21451cb0ef41Sopenharmony_ci stmt_for_coverage, catch_prediction); 21461cb0ef41Sopenharmony_ci 21471cb0ef41Sopenharmony_ci // Preserve the context in a dedicated register, so that it can be restored 21481cb0ef41Sopenharmony_ci // when the handler is entered by the stack-unwinding machinery. 21491cb0ef41Sopenharmony_ci // TODO(ignition): Be smarter about register allocation. 21501cb0ef41Sopenharmony_ci Register context = register_allocator()->NewRegister(); 21511cb0ef41Sopenharmony_ci builder()->MoveRegister(Register::current_context(), context); 21521cb0ef41Sopenharmony_ci 21531cb0ef41Sopenharmony_ci // Evaluate the try-block inside a control scope. This simulates a handler 21541cb0ef41Sopenharmony_ci // that is intercepting 'throw' control commands. 21551cb0ef41Sopenharmony_ci try_control_builder.BeginTry(context); 21561cb0ef41Sopenharmony_ci { 21571cb0ef41Sopenharmony_ci ControlScopeForTryCatch scope(this, &try_control_builder); 21581cb0ef41Sopenharmony_ci try_body_func(); 21591cb0ef41Sopenharmony_ci } 21601cb0ef41Sopenharmony_ci try_control_builder.EndTry(); 21611cb0ef41Sopenharmony_ci 21621cb0ef41Sopenharmony_ci catch_body_func(context); 21631cb0ef41Sopenharmony_ci 21641cb0ef41Sopenharmony_ci try_control_builder.EndCatch(); 21651cb0ef41Sopenharmony_ci} 21661cb0ef41Sopenharmony_ci 21671cb0ef41Sopenharmony_citemplate <typename TryBodyFunc, typename FinallyBodyFunc> 21681cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildTryFinally( 21691cb0ef41Sopenharmony_ci TryBodyFunc try_body_func, FinallyBodyFunc finally_body_func, 21701cb0ef41Sopenharmony_ci HandlerTable::CatchPrediction catch_prediction, 21711cb0ef41Sopenharmony_ci TryFinallyStatement* stmt_for_coverage) { 21721cb0ef41Sopenharmony_ci if (builder()->RemainderOfBlockIsDead()) return; 21731cb0ef41Sopenharmony_ci 21741cb0ef41Sopenharmony_ci // We can't know whether the finally block will override ("catch") an 21751cb0ef41Sopenharmony_ci // exception thrown in the try block, so we just adopt the outer prediction. 21761cb0ef41Sopenharmony_ci TryFinallyBuilder try_control_builder( 21771cb0ef41Sopenharmony_ci builder(), 21781cb0ef41Sopenharmony_ci stmt_for_coverage == nullptr ? nullptr : block_coverage_builder_, 21791cb0ef41Sopenharmony_ci stmt_for_coverage, catch_prediction); 21801cb0ef41Sopenharmony_ci 21811cb0ef41Sopenharmony_ci // We keep a record of all paths that enter the finally-block to be able to 21821cb0ef41Sopenharmony_ci // dispatch to the correct continuation point after the statements in the 21831cb0ef41Sopenharmony_ci // finally-block have been evaluated. 21841cb0ef41Sopenharmony_ci // 21851cb0ef41Sopenharmony_ci // The try-finally construct can enter the finally-block in three ways: 21861cb0ef41Sopenharmony_ci // 1. By exiting the try-block normally, falling through at the end. 21871cb0ef41Sopenharmony_ci // 2. By exiting the try-block with a function-local control flow transfer 21881cb0ef41Sopenharmony_ci // (i.e. through break/continue/return statements). 21891cb0ef41Sopenharmony_ci // 3. By exiting the try-block with a thrown exception. 21901cb0ef41Sopenharmony_ci // 21911cb0ef41Sopenharmony_ci // The result register semantics depend on how the block was entered: 21921cb0ef41Sopenharmony_ci // - ReturnStatement: It represents the return value being returned. 21931cb0ef41Sopenharmony_ci // - ThrowStatement: It represents the exception being thrown. 21941cb0ef41Sopenharmony_ci // - BreakStatement/ContinueStatement: Undefined and not used. 21951cb0ef41Sopenharmony_ci // - Falling through into finally-block: Undefined and not used. 21961cb0ef41Sopenharmony_ci Register token = register_allocator()->NewRegister(); 21971cb0ef41Sopenharmony_ci Register result = register_allocator()->NewRegister(); 21981cb0ef41Sopenharmony_ci ControlScope::DeferredCommands commands(this, token, result); 21991cb0ef41Sopenharmony_ci 22001cb0ef41Sopenharmony_ci // Preserve the context in a dedicated register, so that it can be restored 22011cb0ef41Sopenharmony_ci // when the handler is entered by the stack-unwinding machinery. 22021cb0ef41Sopenharmony_ci // TODO(ignition): Be smarter about register allocation. 22031cb0ef41Sopenharmony_ci Register context = register_allocator()->NewRegister(); 22041cb0ef41Sopenharmony_ci builder()->MoveRegister(Register::current_context(), context); 22051cb0ef41Sopenharmony_ci 22061cb0ef41Sopenharmony_ci // Evaluate the try-block inside a control scope. This simulates a handler 22071cb0ef41Sopenharmony_ci // that is intercepting all control commands. 22081cb0ef41Sopenharmony_ci try_control_builder.BeginTry(context); 22091cb0ef41Sopenharmony_ci { 22101cb0ef41Sopenharmony_ci ControlScopeForTryFinally scope(this, &try_control_builder, &commands); 22111cb0ef41Sopenharmony_ci try_body_func(); 22121cb0ef41Sopenharmony_ci } 22131cb0ef41Sopenharmony_ci try_control_builder.EndTry(); 22141cb0ef41Sopenharmony_ci 22151cb0ef41Sopenharmony_ci // Record fall-through and exception cases. 22161cb0ef41Sopenharmony_ci commands.RecordFallThroughPath(); 22171cb0ef41Sopenharmony_ci try_control_builder.LeaveTry(); 22181cb0ef41Sopenharmony_ci try_control_builder.BeginHandler(); 22191cb0ef41Sopenharmony_ci commands.RecordHandlerReThrowPath(); 22201cb0ef41Sopenharmony_ci 22211cb0ef41Sopenharmony_ci // Pending message object is saved on entry. 22221cb0ef41Sopenharmony_ci try_control_builder.BeginFinally(); 22231cb0ef41Sopenharmony_ci Register message = context; // Reuse register. 22241cb0ef41Sopenharmony_ci 22251cb0ef41Sopenharmony_ci // Clear message object as we enter the finally block. 22261cb0ef41Sopenharmony_ci builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister( 22271cb0ef41Sopenharmony_ci message); 22281cb0ef41Sopenharmony_ci 22291cb0ef41Sopenharmony_ci // Evaluate the finally-block. 22301cb0ef41Sopenharmony_ci finally_body_func(token); 22311cb0ef41Sopenharmony_ci try_control_builder.EndFinally(); 22321cb0ef41Sopenharmony_ci 22331cb0ef41Sopenharmony_ci // Pending message object is restored on exit. 22341cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(message).SetPendingMessage(); 22351cb0ef41Sopenharmony_ci 22361cb0ef41Sopenharmony_ci // Dynamic dispatch after the finally-block. 22371cb0ef41Sopenharmony_ci commands.ApplyDeferredCommands(); 22381cb0ef41Sopenharmony_ci} 22391cb0ef41Sopenharmony_ci 22401cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitIterationBody(IterationStatement* stmt, 22411cb0ef41Sopenharmony_ci LoopBuilder* loop_builder) { 22421cb0ef41Sopenharmony_ci loop_builder->LoopBody(); 22431cb0ef41Sopenharmony_ci ControlScopeForIteration execution_control(this, stmt, loop_builder); 22441cb0ef41Sopenharmony_ci Visit(stmt->body()); 22451cb0ef41Sopenharmony_ci loop_builder->BindContinueTarget(); 22461cb0ef41Sopenharmony_ci} 22471cb0ef41Sopenharmony_ci 22481cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { 22491cb0ef41Sopenharmony_ci LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); 22501cb0ef41Sopenharmony_ci if (stmt->cond()->ToBooleanIsFalse()) { 22511cb0ef41Sopenharmony_ci // Since we know that the condition is false, we don't create a loop. 22521cb0ef41Sopenharmony_ci // Therefore, we don't create a LoopScope (and thus we don't create a header 22531cb0ef41Sopenharmony_ci // and a JumpToHeader). However, we still need to iterate once through the 22541cb0ef41Sopenharmony_ci // body. 22551cb0ef41Sopenharmony_ci VisitIterationBody(stmt, &loop_builder); 22561cb0ef41Sopenharmony_ci } else if (stmt->cond()->ToBooleanIsTrue()) { 22571cb0ef41Sopenharmony_ci LoopScope loop_scope(this, &loop_builder); 22581cb0ef41Sopenharmony_ci VisitIterationBody(stmt, &loop_builder); 22591cb0ef41Sopenharmony_ci } else { 22601cb0ef41Sopenharmony_ci LoopScope loop_scope(this, &loop_builder); 22611cb0ef41Sopenharmony_ci VisitIterationBody(stmt, &loop_builder); 22621cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(stmt->cond()); 22631cb0ef41Sopenharmony_ci BytecodeLabels loop_backbranch(zone()); 22641cb0ef41Sopenharmony_ci VisitForTest(stmt->cond(), &loop_backbranch, loop_builder.break_labels(), 22651cb0ef41Sopenharmony_ci TestFallthrough::kThen); 22661cb0ef41Sopenharmony_ci loop_backbranch.Bind(builder()); 22671cb0ef41Sopenharmony_ci } 22681cb0ef41Sopenharmony_ci} 22691cb0ef41Sopenharmony_ci 22701cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { 22711cb0ef41Sopenharmony_ci LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); 22721cb0ef41Sopenharmony_ci 22731cb0ef41Sopenharmony_ci if (stmt->cond()->ToBooleanIsFalse()) { 22741cb0ef41Sopenharmony_ci // If the condition is false there is no need to generate the loop. 22751cb0ef41Sopenharmony_ci return; 22761cb0ef41Sopenharmony_ci } 22771cb0ef41Sopenharmony_ci 22781cb0ef41Sopenharmony_ci LoopScope loop_scope(this, &loop_builder); 22791cb0ef41Sopenharmony_ci if (!stmt->cond()->ToBooleanIsTrue()) { 22801cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(stmt->cond()); 22811cb0ef41Sopenharmony_ci BytecodeLabels loop_body(zone()); 22821cb0ef41Sopenharmony_ci VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(), 22831cb0ef41Sopenharmony_ci TestFallthrough::kThen); 22841cb0ef41Sopenharmony_ci loop_body.Bind(builder()); 22851cb0ef41Sopenharmony_ci } 22861cb0ef41Sopenharmony_ci VisitIterationBody(stmt, &loop_builder); 22871cb0ef41Sopenharmony_ci} 22881cb0ef41Sopenharmony_ci 22891cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitForStatement(ForStatement* stmt) { 22901cb0ef41Sopenharmony_ci if (stmt->init() != nullptr) { 22911cb0ef41Sopenharmony_ci Visit(stmt->init()); 22921cb0ef41Sopenharmony_ci } 22931cb0ef41Sopenharmony_ci 22941cb0ef41Sopenharmony_ci LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); 22951cb0ef41Sopenharmony_ci if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { 22961cb0ef41Sopenharmony_ci // If the condition is known to be false there is no need to generate 22971cb0ef41Sopenharmony_ci // body, next or condition blocks. Init block should be generated. 22981cb0ef41Sopenharmony_ci return; 22991cb0ef41Sopenharmony_ci } 23001cb0ef41Sopenharmony_ci 23011cb0ef41Sopenharmony_ci LoopScope loop_scope(this, &loop_builder); 23021cb0ef41Sopenharmony_ci if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { 23031cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(stmt->cond()); 23041cb0ef41Sopenharmony_ci BytecodeLabels loop_body(zone()); 23051cb0ef41Sopenharmony_ci VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(), 23061cb0ef41Sopenharmony_ci TestFallthrough::kThen); 23071cb0ef41Sopenharmony_ci loop_body.Bind(builder()); 23081cb0ef41Sopenharmony_ci } 23091cb0ef41Sopenharmony_ci VisitIterationBody(stmt, &loop_builder); 23101cb0ef41Sopenharmony_ci if (stmt->next() != nullptr) { 23111cb0ef41Sopenharmony_ci builder()->SetStatementPosition(stmt->next()); 23121cb0ef41Sopenharmony_ci Visit(stmt->next()); 23131cb0ef41Sopenharmony_ci } 23141cb0ef41Sopenharmony_ci} 23151cb0ef41Sopenharmony_ci 23161cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { 23171cb0ef41Sopenharmony_ci if (stmt->subject()->IsNullLiteral() || 23181cb0ef41Sopenharmony_ci stmt->subject()->IsUndefinedLiteral()) { 23191cb0ef41Sopenharmony_ci // ForIn generates lots of code, skip if it wouldn't produce any effects. 23201cb0ef41Sopenharmony_ci return; 23211cb0ef41Sopenharmony_ci } 23221cb0ef41Sopenharmony_ci 23231cb0ef41Sopenharmony_ci BytecodeLabel subject_undefined_label; 23241cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddForInSlot(); 23251cb0ef41Sopenharmony_ci 23261cb0ef41Sopenharmony_ci // Prepare the state for executing ForIn. 23271cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(stmt->subject()); 23281cb0ef41Sopenharmony_ci VisitForAccumulatorValue(stmt->subject()); 23291cb0ef41Sopenharmony_ci builder()->JumpIfUndefinedOrNull(&subject_undefined_label); 23301cb0ef41Sopenharmony_ci Register receiver = register_allocator()->NewRegister(); 23311cb0ef41Sopenharmony_ci builder()->ToObject(receiver); 23321cb0ef41Sopenharmony_ci 23331cb0ef41Sopenharmony_ci // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext. 23341cb0ef41Sopenharmony_ci RegisterList triple = register_allocator()->NewRegisterList(3); 23351cb0ef41Sopenharmony_ci Register cache_length = triple[2]; 23361cb0ef41Sopenharmony_ci builder()->ForInEnumerate(receiver); 23371cb0ef41Sopenharmony_ci builder()->ForInPrepare(triple, feedback_index(slot)); 23381cb0ef41Sopenharmony_ci 23391cb0ef41Sopenharmony_ci // Set up loop counter 23401cb0ef41Sopenharmony_ci Register index = register_allocator()->NewRegister(); 23411cb0ef41Sopenharmony_ci builder()->LoadLiteral(Smi::zero()); 23421cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(index); 23431cb0ef41Sopenharmony_ci 23441cb0ef41Sopenharmony_ci // The loop 23451cb0ef41Sopenharmony_ci { 23461cb0ef41Sopenharmony_ci LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); 23471cb0ef41Sopenharmony_ci LoopScope loop_scope(this, &loop_builder); 23481cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(stmt->each()); 23491cb0ef41Sopenharmony_ci builder()->ForInContinue(index, cache_length); 23501cb0ef41Sopenharmony_ci loop_builder.BreakIfFalse(ToBooleanMode::kAlreadyBoolean); 23511cb0ef41Sopenharmony_ci builder()->ForInNext(receiver, index, triple.Truncate(2), 23521cb0ef41Sopenharmony_ci feedback_index(slot)); 23531cb0ef41Sopenharmony_ci loop_builder.ContinueIfUndefined(); 23541cb0ef41Sopenharmony_ci 23551cb0ef41Sopenharmony_ci // Assign accumulator value to the 'each' target. 23561cb0ef41Sopenharmony_ci { 23571cb0ef41Sopenharmony_ci EffectResultScope scope(this); 23581cb0ef41Sopenharmony_ci // Make sure to preserve the accumulator across the PrepareAssignmentLhs 23591cb0ef41Sopenharmony_ci // call. 23601cb0ef41Sopenharmony_ci AssignmentLhsData lhs_data = PrepareAssignmentLhs( 23611cb0ef41Sopenharmony_ci stmt->each(), AccumulatorPreservingMode::kPreserve); 23621cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(stmt->each()); 23631cb0ef41Sopenharmony_ci BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal); 23641cb0ef41Sopenharmony_ci } 23651cb0ef41Sopenharmony_ci 23661cb0ef41Sopenharmony_ci VisitIterationBody(stmt, &loop_builder); 23671cb0ef41Sopenharmony_ci builder()->ForInStep(index); 23681cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(index); 23691cb0ef41Sopenharmony_ci } 23701cb0ef41Sopenharmony_ci builder()->Bind(&subject_undefined_label); 23711cb0ef41Sopenharmony_ci} 23721cb0ef41Sopenharmony_ci 23731cb0ef41Sopenharmony_ci// Desugar a for-of statement into an application of the iteration protocol. 23741cb0ef41Sopenharmony_ci// 23751cb0ef41Sopenharmony_ci// for (EACH of SUBJECT) BODY 23761cb0ef41Sopenharmony_ci// 23771cb0ef41Sopenharmony_ci// becomes 23781cb0ef41Sopenharmony_ci// 23791cb0ef41Sopenharmony_ci// iterator = %GetIterator(SUBJECT) 23801cb0ef41Sopenharmony_ci// try { 23811cb0ef41Sopenharmony_ci// 23821cb0ef41Sopenharmony_ci// loop { 23831cb0ef41Sopenharmony_ci// // Make sure we are considered 'done' if .next(), .done or .value fail. 23841cb0ef41Sopenharmony_ci// done = true 23851cb0ef41Sopenharmony_ci// value = iterator.next() 23861cb0ef41Sopenharmony_ci// if (value.done) break; 23871cb0ef41Sopenharmony_ci// value = value.value 23881cb0ef41Sopenharmony_ci// done = false 23891cb0ef41Sopenharmony_ci// 23901cb0ef41Sopenharmony_ci// EACH = value 23911cb0ef41Sopenharmony_ci// BODY 23921cb0ef41Sopenharmony_ci// } 23931cb0ef41Sopenharmony_ci// done = true 23941cb0ef41Sopenharmony_ci// 23951cb0ef41Sopenharmony_ci// } catch(e) { 23961cb0ef41Sopenharmony_ci// iteration_continuation = RETHROW 23971cb0ef41Sopenharmony_ci// } finally { 23981cb0ef41Sopenharmony_ci// %FinalizeIteration(iterator, done, iteration_continuation) 23991cb0ef41Sopenharmony_ci// } 24001cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { 24011cb0ef41Sopenharmony_ci EffectResultScope effect_scope(this); 24021cb0ef41Sopenharmony_ci 24031cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(stmt->subject()); 24041cb0ef41Sopenharmony_ci VisitForAccumulatorValue(stmt->subject()); 24051cb0ef41Sopenharmony_ci 24061cb0ef41Sopenharmony_ci // Store the iterator in a dedicated register so that it can be closed on 24071cb0ef41Sopenharmony_ci // exit, and the 'done' value in a dedicated register so that it can be 24081cb0ef41Sopenharmony_ci // changed and accessed independently of the iteration result. 24091cb0ef41Sopenharmony_ci IteratorRecord iterator = BuildGetIteratorRecord(stmt->type()); 24101cb0ef41Sopenharmony_ci Register done = register_allocator()->NewRegister(); 24111cb0ef41Sopenharmony_ci builder()->LoadFalse(); 24121cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(done); 24131cb0ef41Sopenharmony_ci 24141cb0ef41Sopenharmony_ci BuildTryFinally( 24151cb0ef41Sopenharmony_ci // Try block. 24161cb0ef41Sopenharmony_ci [&]() { 24171cb0ef41Sopenharmony_ci Register next_result = register_allocator()->NewRegister(); 24181cb0ef41Sopenharmony_ci 24191cb0ef41Sopenharmony_ci LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); 24201cb0ef41Sopenharmony_ci LoopScope loop_scope(this, &loop_builder); 24211cb0ef41Sopenharmony_ci 24221cb0ef41Sopenharmony_ci builder()->LoadTrue().StoreAccumulatorInRegister(done); 24231cb0ef41Sopenharmony_ci 24241cb0ef41Sopenharmony_ci // Call the iterator's .next() method. Break from the loop if the `done` 24251cb0ef41Sopenharmony_ci // property is truthy, otherwise load the value from the iterator result 24261cb0ef41Sopenharmony_ci // and append the argument. 24271cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(stmt->each()); 24281cb0ef41Sopenharmony_ci BuildIteratorNext(iterator, next_result); 24291cb0ef41Sopenharmony_ci builder()->LoadNamedProperty( 24301cb0ef41Sopenharmony_ci next_result, ast_string_constants()->done_string(), 24311cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLoadICSlot())); 24321cb0ef41Sopenharmony_ci loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean); 24331cb0ef41Sopenharmony_ci 24341cb0ef41Sopenharmony_ci builder() 24351cb0ef41Sopenharmony_ci // value = value.value 24361cb0ef41Sopenharmony_ci ->LoadNamedProperty( 24371cb0ef41Sopenharmony_ci next_result, ast_string_constants()->value_string(), 24381cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLoadICSlot())); 24391cb0ef41Sopenharmony_ci // done = false, before the assignment to each happens, so that done is 24401cb0ef41Sopenharmony_ci // false if the assignment throws. 24411cb0ef41Sopenharmony_ci builder() 24421cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(next_result) 24431cb0ef41Sopenharmony_ci .LoadFalse() 24441cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(done); 24451cb0ef41Sopenharmony_ci 24461cb0ef41Sopenharmony_ci // Assign to the 'each' target. 24471cb0ef41Sopenharmony_ci AssignmentLhsData lhs_data = PrepareAssignmentLhs(stmt->each()); 24481cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(next_result); 24491cb0ef41Sopenharmony_ci BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal); 24501cb0ef41Sopenharmony_ci 24511cb0ef41Sopenharmony_ci VisitIterationBody(stmt, &loop_builder); 24521cb0ef41Sopenharmony_ci }, 24531cb0ef41Sopenharmony_ci // Finally block. 24541cb0ef41Sopenharmony_ci [&](Register iteration_continuation_token) { 24551cb0ef41Sopenharmony_ci // Finish the iteration in the finally block. 24561cb0ef41Sopenharmony_ci BuildFinalizeIteration(iterator, done, iteration_continuation_token); 24571cb0ef41Sopenharmony_ci }, 24581cb0ef41Sopenharmony_ci HandlerTable::UNCAUGHT); 24591cb0ef41Sopenharmony_ci} 24601cb0ef41Sopenharmony_ci 24611cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { 24621cb0ef41Sopenharmony_ci // Update catch prediction tracking. The updated catch_prediction value lasts 24631cb0ef41Sopenharmony_ci // until the end of the try_block in the AST node, and does not apply to the 24641cb0ef41Sopenharmony_ci // catch_block. 24651cb0ef41Sopenharmony_ci HandlerTable::CatchPrediction outer_catch_prediction = catch_prediction(); 24661cb0ef41Sopenharmony_ci set_catch_prediction(stmt->GetCatchPrediction(outer_catch_prediction)); 24671cb0ef41Sopenharmony_ci 24681cb0ef41Sopenharmony_ci BuildTryCatch( 24691cb0ef41Sopenharmony_ci // Try body. 24701cb0ef41Sopenharmony_ci [&]() { 24711cb0ef41Sopenharmony_ci Visit(stmt->try_block()); 24721cb0ef41Sopenharmony_ci set_catch_prediction(outer_catch_prediction); 24731cb0ef41Sopenharmony_ci }, 24741cb0ef41Sopenharmony_ci // Catch body. 24751cb0ef41Sopenharmony_ci [&](Register context) { 24761cb0ef41Sopenharmony_ci if (stmt->scope()) { 24771cb0ef41Sopenharmony_ci // Create a catch scope that binds the exception. 24781cb0ef41Sopenharmony_ci BuildNewLocalCatchContext(stmt->scope()); 24791cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(context); 24801cb0ef41Sopenharmony_ci } 24811cb0ef41Sopenharmony_ci 24821cb0ef41Sopenharmony_ci // If requested, clear message object as we enter the catch block. 24831cb0ef41Sopenharmony_ci if (stmt->ShouldClearPendingException(outer_catch_prediction)) { 24841cb0ef41Sopenharmony_ci builder()->LoadTheHole().SetPendingMessage(); 24851cb0ef41Sopenharmony_ci } 24861cb0ef41Sopenharmony_ci 24871cb0ef41Sopenharmony_ci // Load the catch context into the accumulator. 24881cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(context); 24891cb0ef41Sopenharmony_ci 24901cb0ef41Sopenharmony_ci // Evaluate the catch-block. 24911cb0ef41Sopenharmony_ci if (stmt->scope()) { 24921cb0ef41Sopenharmony_ci VisitInScope(stmt->catch_block(), stmt->scope()); 24931cb0ef41Sopenharmony_ci } else { 24941cb0ef41Sopenharmony_ci VisitBlock(stmt->catch_block()); 24951cb0ef41Sopenharmony_ci } 24961cb0ef41Sopenharmony_ci }, 24971cb0ef41Sopenharmony_ci catch_prediction(), stmt); 24981cb0ef41Sopenharmony_ci} 24991cb0ef41Sopenharmony_ci 25001cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 25011cb0ef41Sopenharmony_ci BuildTryFinally( 25021cb0ef41Sopenharmony_ci // Try block. 25031cb0ef41Sopenharmony_ci [&]() { Visit(stmt->try_block()); }, 25041cb0ef41Sopenharmony_ci // Finally block. 25051cb0ef41Sopenharmony_ci [&](Register body_continuation_token) { Visit(stmt->finally_block()); }, 25061cb0ef41Sopenharmony_ci catch_prediction(), stmt); 25071cb0ef41Sopenharmony_ci} 25081cb0ef41Sopenharmony_ci 25091cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { 25101cb0ef41Sopenharmony_ci builder()->SetStatementPosition(stmt); 25111cb0ef41Sopenharmony_ci builder()->Debugger(); 25121cb0ef41Sopenharmony_ci} 25131cb0ef41Sopenharmony_ci 25141cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { 25151cb0ef41Sopenharmony_ci DCHECK_EQ(expr->scope()->outer_scope(), current_scope()); 25161cb0ef41Sopenharmony_ci uint8_t flags = CreateClosureFlags::Encode( 25171cb0ef41Sopenharmony_ci expr->pretenure(), closure_scope()->is_function_scope(), 25181cb0ef41Sopenharmony_ci info()->flags().might_always_opt()); 25191cb0ef41Sopenharmony_ci size_t entry = builder()->AllocateDeferredConstantPoolEntry(); 25201cb0ef41Sopenharmony_ci builder()->CreateClosure(entry, GetCachedCreateClosureSlot(expr), flags); 25211cb0ef41Sopenharmony_ci function_literals_.push_back(std::make_pair(expr, entry)); 25221cb0ef41Sopenharmony_ci AddToEagerLiteralsIfEager(expr); 25231cb0ef41Sopenharmony_ci} 25241cb0ef41Sopenharmony_ci 25251cb0ef41Sopenharmony_civoid BytecodeGenerator::AddToEagerLiteralsIfEager(FunctionLiteral* literal) { 25261cb0ef41Sopenharmony_ci // Only parallel compile when there's a script (not the case for source 25271cb0ef41Sopenharmony_ci // position collection). 25281cb0ef41Sopenharmony_ci if (!script_.is_null() && literal->should_parallel_compile()) { 25291cb0ef41Sopenharmony_ci // If we should normally be eagerly compiling this function, we must be here 25301cb0ef41Sopenharmony_ci // because of post_parallel_compile_tasks_for_eager_toplevel. 25311cb0ef41Sopenharmony_ci DCHECK_IMPLIES( 25321cb0ef41Sopenharmony_ci literal->ShouldEagerCompile(), 25331cb0ef41Sopenharmony_ci info()->flags().post_parallel_compile_tasks_for_eager_toplevel()); 25341cb0ef41Sopenharmony_ci // There exists a lazy compile dispatcher. 25351cb0ef41Sopenharmony_ci DCHECK(info()->dispatcher()); 25361cb0ef41Sopenharmony_ci // There exists a cloneable character stream. 25371cb0ef41Sopenharmony_ci DCHECK(info()->character_stream()->can_be_cloned_for_parallel_access()); 25381cb0ef41Sopenharmony_ci 25391cb0ef41Sopenharmony_ci UnparkedScope scope(local_isolate_); 25401cb0ef41Sopenharmony_ci // If there doesn't already exist a SharedFunctionInfo for this function, 25411cb0ef41Sopenharmony_ci // then create one and enqueue it. Otherwise, we're reparsing (e.g. for the 25421cb0ef41Sopenharmony_ci // debugger, source position collection, call printing, recompile after 25431cb0ef41Sopenharmony_ci // flushing, etc.) and don't want to over-compile. 25441cb0ef41Sopenharmony_ci Handle<SharedFunctionInfo> shared_info; 25451cb0ef41Sopenharmony_ci if (!Script::FindSharedFunctionInfo(script_, local_isolate_, literal) 25461cb0ef41Sopenharmony_ci .ToHandle(&shared_info)) { 25471cb0ef41Sopenharmony_ci shared_info = 25481cb0ef41Sopenharmony_ci Compiler::GetSharedFunctionInfo(literal, script_, local_isolate_); 25491cb0ef41Sopenharmony_ci info()->dispatcher()->Enqueue(local_isolate_, shared_info, 25501cb0ef41Sopenharmony_ci info()->character_stream()->Clone()); 25511cb0ef41Sopenharmony_ci } 25521cb0ef41Sopenharmony_ci } else if (eager_inner_literals_ && literal->ShouldEagerCompile()) { 25531cb0ef41Sopenharmony_ci DCHECK(!IsInEagerLiterals(literal, *eager_inner_literals_)); 25541cb0ef41Sopenharmony_ci DCHECK(!literal->should_parallel_compile()); 25551cb0ef41Sopenharmony_ci eager_inner_literals_->push_back(literal); 25561cb0ef41Sopenharmony_ci } 25571cb0ef41Sopenharmony_ci} 25581cb0ef41Sopenharmony_ci 25591cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { 25601cb0ef41Sopenharmony_ci size_t class_boilerplate_entry = 25611cb0ef41Sopenharmony_ci builder()->AllocateDeferredConstantPoolEntry(); 25621cb0ef41Sopenharmony_ci class_literals_.push_back(std::make_pair(expr, class_boilerplate_entry)); 25631cb0ef41Sopenharmony_ci 25641cb0ef41Sopenharmony_ci VisitDeclarations(expr->scope()->declarations()); 25651cb0ef41Sopenharmony_ci Register class_constructor = register_allocator()->NewRegister(); 25661cb0ef41Sopenharmony_ci 25671cb0ef41Sopenharmony_ci // Create the class brand symbol and store it on the context during class 25681cb0ef41Sopenharmony_ci // evaluation. This will be stored in the instance later in the constructor. 25691cb0ef41Sopenharmony_ci // We do this early so that invalid access to private methods or accessors 25701cb0ef41Sopenharmony_ci // in computed property keys throw. 25711cb0ef41Sopenharmony_ci if (expr->scope()->brand() != nullptr) { 25721cb0ef41Sopenharmony_ci Register brand = register_allocator()->NewRegister(); 25731cb0ef41Sopenharmony_ci const AstRawString* class_name = 25741cb0ef41Sopenharmony_ci expr->scope()->class_variable() != nullptr 25751cb0ef41Sopenharmony_ci ? expr->scope()->class_variable()->raw_name() 25761cb0ef41Sopenharmony_ci : ast_string_constants()->anonymous_string(); 25771cb0ef41Sopenharmony_ci builder() 25781cb0ef41Sopenharmony_ci ->LoadLiteral(class_name) 25791cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(brand) 25801cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kCreatePrivateBrandSymbol, brand); 25811cb0ef41Sopenharmony_ci BuildVariableAssignment(expr->scope()->brand(), Token::INIT, 25821cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 25831cb0ef41Sopenharmony_ci } 25841cb0ef41Sopenharmony_ci 25851cb0ef41Sopenharmony_ci AccessorTable<ClassLiteral::Property> private_accessors(zone()); 25861cb0ef41Sopenharmony_ci for (int i = 0; i < expr->private_members()->length(); i++) { 25871cb0ef41Sopenharmony_ci ClassLiteral::Property* property = expr->private_members()->at(i); 25881cb0ef41Sopenharmony_ci DCHECK(property->is_private()); 25891cb0ef41Sopenharmony_ci switch (property->kind()) { 25901cb0ef41Sopenharmony_ci case ClassLiteral::Property::FIELD: { 25911cb0ef41Sopenharmony_ci // Initialize the private field variables early. 25921cb0ef41Sopenharmony_ci // Create the private name symbols for fields during class 25931cb0ef41Sopenharmony_ci // evaluation and store them on the context. These will be 25941cb0ef41Sopenharmony_ci // used as keys later during instance or static initialization. 25951cb0ef41Sopenharmony_ci RegisterAllocationScope private_name_register_scope(this); 25961cb0ef41Sopenharmony_ci Register private_name = register_allocator()->NewRegister(); 25971cb0ef41Sopenharmony_ci VisitForRegisterValue(property->key(), private_name); 25981cb0ef41Sopenharmony_ci builder() 25991cb0ef41Sopenharmony_ci ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 26001cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(private_name) 26011cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kCreatePrivateNameSymbol, private_name); 26021cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(property->private_name_var()); 26031cb0ef41Sopenharmony_ci BuildVariableAssignment(property->private_name_var(), Token::INIT, 26041cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 26051cb0ef41Sopenharmony_ci break; 26061cb0ef41Sopenharmony_ci } 26071cb0ef41Sopenharmony_ci case ClassLiteral::Property::METHOD: { 26081cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 26091cb0ef41Sopenharmony_ci VisitForAccumulatorValue(property->value()); 26101cb0ef41Sopenharmony_ci BuildVariableAssignment(property->private_name_var(), Token::INIT, 26111cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 26121cb0ef41Sopenharmony_ci break; 26131cb0ef41Sopenharmony_ci } 26141cb0ef41Sopenharmony_ci // Collect private accessors into a table to merge the creation of 26151cb0ef41Sopenharmony_ci // those closures later. 26161cb0ef41Sopenharmony_ci case ClassLiteral::Property::GETTER: { 26171cb0ef41Sopenharmony_ci Literal* key = property->key()->AsLiteral(); 26181cb0ef41Sopenharmony_ci DCHECK_NULL(private_accessors.LookupOrInsert(key)->getter); 26191cb0ef41Sopenharmony_ci private_accessors.LookupOrInsert(key)->getter = property; 26201cb0ef41Sopenharmony_ci break; 26211cb0ef41Sopenharmony_ci } 26221cb0ef41Sopenharmony_ci case ClassLiteral::Property::SETTER: { 26231cb0ef41Sopenharmony_ci Literal* key = property->key()->AsLiteral(); 26241cb0ef41Sopenharmony_ci DCHECK_NULL(private_accessors.LookupOrInsert(key)->setter); 26251cb0ef41Sopenharmony_ci private_accessors.LookupOrInsert(key)->setter = property; 26261cb0ef41Sopenharmony_ci break; 26271cb0ef41Sopenharmony_ci } 26281cb0ef41Sopenharmony_ci default: 26291cb0ef41Sopenharmony_ci UNREACHABLE(); 26301cb0ef41Sopenharmony_ci } 26311cb0ef41Sopenharmony_ci } 26321cb0ef41Sopenharmony_ci 26331cb0ef41Sopenharmony_ci { 26341cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 26351cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewGrowableRegisterList(); 26361cb0ef41Sopenharmony_ci 26371cb0ef41Sopenharmony_ci Register class_boilerplate = register_allocator()->GrowRegisterList(&args); 26381cb0ef41Sopenharmony_ci Register class_constructor_in_args = 26391cb0ef41Sopenharmony_ci register_allocator()->GrowRegisterList(&args); 26401cb0ef41Sopenharmony_ci Register super_class = register_allocator()->GrowRegisterList(&args); 26411cb0ef41Sopenharmony_ci DCHECK_EQ(ClassBoilerplate::kFirstDynamicArgumentIndex, 26421cb0ef41Sopenharmony_ci args.register_count()); 26431cb0ef41Sopenharmony_ci 26441cb0ef41Sopenharmony_ci VisitForAccumulatorValueOrTheHole(expr->extends()); 26451cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(super_class); 26461cb0ef41Sopenharmony_ci 26471cb0ef41Sopenharmony_ci VisitFunctionLiteral(expr->constructor()); 26481cb0ef41Sopenharmony_ci builder() 26491cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(class_constructor) 26501cb0ef41Sopenharmony_ci .MoveRegister(class_constructor, class_constructor_in_args) 26511cb0ef41Sopenharmony_ci .LoadConstantPoolEntry(class_boilerplate_entry) 26521cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(class_boilerplate); 26531cb0ef41Sopenharmony_ci 26541cb0ef41Sopenharmony_ci // Create computed names and method values nodes to store into the literal. 26551cb0ef41Sopenharmony_ci for (int i = 0; i < expr->public_members()->length(); i++) { 26561cb0ef41Sopenharmony_ci ClassLiteral::Property* property = expr->public_members()->at(i); 26571cb0ef41Sopenharmony_ci if (property->is_computed_name()) { 26581cb0ef41Sopenharmony_ci Register key = register_allocator()->GrowRegisterList(&args); 26591cb0ef41Sopenharmony_ci 26601cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(property->key()); 26611cb0ef41Sopenharmony_ci BuildLoadPropertyKey(property, key); 26621cb0ef41Sopenharmony_ci if (property->is_static()) { 26631cb0ef41Sopenharmony_ci // The static prototype property is read only. We handle the non 26641cb0ef41Sopenharmony_ci // computed property name case in the parser. Since this is the only 26651cb0ef41Sopenharmony_ci // case where we need to check for an own read only property we 26661cb0ef41Sopenharmony_ci // special case this so we do not need to do this for every property. 26671cb0ef41Sopenharmony_ci 26681cb0ef41Sopenharmony_ci FeedbackSlot slot = GetDummyCompareICSlot(); 26691cb0ef41Sopenharmony_ci BytecodeLabel done; 26701cb0ef41Sopenharmony_ci builder() 26711cb0ef41Sopenharmony_ci ->LoadLiteral(ast_string_constants()->prototype_string()) 26721cb0ef41Sopenharmony_ci .CompareOperation(Token::Value::EQ_STRICT, key, 26731cb0ef41Sopenharmony_ci feedback_index(slot)) 26741cb0ef41Sopenharmony_ci .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done) 26751cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kThrowStaticPrototypeError) 26761cb0ef41Sopenharmony_ci .Bind(&done); 26771cb0ef41Sopenharmony_ci } 26781cb0ef41Sopenharmony_ci 26791cb0ef41Sopenharmony_ci if (property->kind() == ClassLiteral::Property::FIELD) { 26801cb0ef41Sopenharmony_ci DCHECK(!property->is_private()); 26811cb0ef41Sopenharmony_ci // Initialize field's name variable with the computed name. 26821cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(property->computed_name_var()); 26831cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(key); 26841cb0ef41Sopenharmony_ci BuildVariableAssignment(property->computed_name_var(), Token::INIT, 26851cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 26861cb0ef41Sopenharmony_ci } 26871cb0ef41Sopenharmony_ci } 26881cb0ef41Sopenharmony_ci 26891cb0ef41Sopenharmony_ci DCHECK(!property->is_private()); 26901cb0ef41Sopenharmony_ci 26911cb0ef41Sopenharmony_ci if (property->kind() == ClassLiteral::Property::FIELD) { 26921cb0ef41Sopenharmony_ci // We don't compute field's value here, but instead do it in the 26931cb0ef41Sopenharmony_ci // initializer function. 26941cb0ef41Sopenharmony_ci continue; 26951cb0ef41Sopenharmony_ci } 26961cb0ef41Sopenharmony_ci 26971cb0ef41Sopenharmony_ci Register value = register_allocator()->GrowRegisterList(&args); 26981cb0ef41Sopenharmony_ci VisitForRegisterValue(property->value(), value); 26991cb0ef41Sopenharmony_ci } 27001cb0ef41Sopenharmony_ci 27011cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kDefineClass, args); 27021cb0ef41Sopenharmony_ci } 27031cb0ef41Sopenharmony_ci Register prototype = register_allocator()->NewRegister(); 27041cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(prototype); 27051cb0ef41Sopenharmony_ci 27061cb0ef41Sopenharmony_ci // Assign to the home object variable. Accumulator already contains the 27071cb0ef41Sopenharmony_ci // prototype. 27081cb0ef41Sopenharmony_ci Variable* home_object_variable = expr->home_object(); 27091cb0ef41Sopenharmony_ci if (home_object_variable != nullptr) { 27101cb0ef41Sopenharmony_ci DCHECK(home_object_variable->is_used()); 27111cb0ef41Sopenharmony_ci DCHECK(home_object_variable->IsContextSlot()); 27121cb0ef41Sopenharmony_ci BuildVariableAssignment(home_object_variable, Token::INIT, 27131cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 27141cb0ef41Sopenharmony_ci } 27151cb0ef41Sopenharmony_ci Variable* static_home_object_variable = expr->static_home_object(); 27161cb0ef41Sopenharmony_ci if (static_home_object_variable != nullptr) { 27171cb0ef41Sopenharmony_ci DCHECK(static_home_object_variable->is_used()); 27181cb0ef41Sopenharmony_ci DCHECK(static_home_object_variable->IsContextSlot()); 27191cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(class_constructor); 27201cb0ef41Sopenharmony_ci BuildVariableAssignment(static_home_object_variable, Token::INIT, 27211cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 27221cb0ef41Sopenharmony_ci } 27231cb0ef41Sopenharmony_ci 27241cb0ef41Sopenharmony_ci // Assign to class variable. 27251cb0ef41Sopenharmony_ci Variable* class_variable = expr->scope()->class_variable(); 27261cb0ef41Sopenharmony_ci if (class_variable != nullptr && class_variable->is_used()) { 27271cb0ef41Sopenharmony_ci DCHECK(class_variable->IsStackLocal() || class_variable->IsContextSlot()); 27281cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(class_constructor); 27291cb0ef41Sopenharmony_ci BuildVariableAssignment(class_variable, Token::INIT, 27301cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 27311cb0ef41Sopenharmony_ci } 27321cb0ef41Sopenharmony_ci 27331cb0ef41Sopenharmony_ci // Define private accessors, using only a single call to the runtime for 27341cb0ef41Sopenharmony_ci // each pair of corresponding getters and setters, in the order the first 27351cb0ef41Sopenharmony_ci // component is declared. 27361cb0ef41Sopenharmony_ci for (auto accessors : private_accessors.ordered_accessors()) { 27371cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 27381cb0ef41Sopenharmony_ci RegisterList accessors_reg = register_allocator()->NewRegisterList(2); 27391cb0ef41Sopenharmony_ci ClassLiteral::Property* getter = accessors.second->getter; 27401cb0ef41Sopenharmony_ci ClassLiteral::Property* setter = accessors.second->setter; 27411cb0ef41Sopenharmony_ci VisitLiteralAccessor(getter, accessors_reg[0]); 27421cb0ef41Sopenharmony_ci VisitLiteralAccessor(setter, accessors_reg[1]); 27431cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kCreatePrivateAccessors, accessors_reg); 27441cb0ef41Sopenharmony_ci Variable* var = getter != nullptr ? getter->private_name_var() 27451cb0ef41Sopenharmony_ci : setter->private_name_var(); 27461cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(var); 27471cb0ef41Sopenharmony_ci BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided); 27481cb0ef41Sopenharmony_ci } 27491cb0ef41Sopenharmony_ci 27501cb0ef41Sopenharmony_ci if (expr->instance_members_initializer_function() != nullptr) { 27511cb0ef41Sopenharmony_ci Register initializer = 27521cb0ef41Sopenharmony_ci VisitForRegisterValue(expr->instance_members_initializer_function()); 27531cb0ef41Sopenharmony_ci 27541cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode()); 27551cb0ef41Sopenharmony_ci builder() 27561cb0ef41Sopenharmony_ci ->LoadAccumulatorWithRegister(initializer) 27571cb0ef41Sopenharmony_ci .StoreClassFieldsInitializer(class_constructor, feedback_index(slot)) 27581cb0ef41Sopenharmony_ci .LoadAccumulatorWithRegister(class_constructor); 27591cb0ef41Sopenharmony_ci } 27601cb0ef41Sopenharmony_ci 27611cb0ef41Sopenharmony_ci if (expr->static_initializer() != nullptr) { 27621cb0ef41Sopenharmony_ci // TODO(gsathya): This can be optimized away to be a part of the 27631cb0ef41Sopenharmony_ci // class boilerplate in the future. The name argument can be 27641cb0ef41Sopenharmony_ci // passed to the DefineClass runtime function and have it set 27651cb0ef41Sopenharmony_ci // there. 27661cb0ef41Sopenharmony_ci if (name.is_valid()) { 27671cb0ef41Sopenharmony_ci Register key = register_allocator()->NewRegister(); 27681cb0ef41Sopenharmony_ci builder() 27691cb0ef41Sopenharmony_ci ->LoadLiteral(ast_string_constants()->name_string()) 27701cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(key); 27711cb0ef41Sopenharmony_ci 27721cb0ef41Sopenharmony_ci DefineKeyedOwnPropertyInLiteralFlags data_property_flags = 27731cb0ef41Sopenharmony_ci DefineKeyedOwnPropertyInLiteralFlag::kNoFlags; 27741cb0ef41Sopenharmony_ci FeedbackSlot slot = 27751cb0ef41Sopenharmony_ci feedback_spec()->AddDefineKeyedOwnPropertyInLiteralICSlot(); 27761cb0ef41Sopenharmony_ci builder() 27771cb0ef41Sopenharmony_ci ->LoadAccumulatorWithRegister(name) 27781cb0ef41Sopenharmony_ci .DefineKeyedOwnPropertyInLiteral(class_constructor, key, 27791cb0ef41Sopenharmony_ci data_property_flags, 27801cb0ef41Sopenharmony_ci feedback_index(slot)); 27811cb0ef41Sopenharmony_ci } 27821cb0ef41Sopenharmony_ci 27831cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(1); 27841cb0ef41Sopenharmony_ci Register initializer = VisitForRegisterValue(expr->static_initializer()); 27851cb0ef41Sopenharmony_ci 27861cb0ef41Sopenharmony_ci builder() 27871cb0ef41Sopenharmony_ci ->MoveRegister(class_constructor, args[0]) 27881cb0ef41Sopenharmony_ci .CallProperty(initializer, args, 27891cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot())); 27901cb0ef41Sopenharmony_ci } 27911cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(class_constructor); 27921cb0ef41Sopenharmony_ci} 27931cb0ef41Sopenharmony_ci 27941cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { 27951cb0ef41Sopenharmony_ci VisitClassLiteral(expr, Register::invalid_value()); 27961cb0ef41Sopenharmony_ci} 27971cb0ef41Sopenharmony_ci 27981cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr, Register name) { 27991cb0ef41Sopenharmony_ci CurrentScope current_scope(this, expr->scope()); 28001cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(expr->scope()); 28011cb0ef41Sopenharmony_ci if (expr->scope()->NeedsContext()) { 28021cb0ef41Sopenharmony_ci // Make sure to associate the source position for the class 28031cb0ef41Sopenharmony_ci // after the block context is created. Otherwise we have a mismatch 28041cb0ef41Sopenharmony_ci // between the scope and the context, where we already are in a 28051cb0ef41Sopenharmony_ci // block context for the class, but not yet in the class scope. 28061cb0ef41Sopenharmony_ci BytecodeSourceInfo source_info = builder()->PopSourcePosition(); 28071cb0ef41Sopenharmony_ci BuildNewLocalBlockContext(expr->scope()); 28081cb0ef41Sopenharmony_ci ContextScope scope(this, expr->scope()); 28091cb0ef41Sopenharmony_ci builder()->PushSourcePosition(source_info); 28101cb0ef41Sopenharmony_ci BuildClassLiteral(expr, name); 28111cb0ef41Sopenharmony_ci } else { 28121cb0ef41Sopenharmony_ci BuildClassLiteral(expr, name); 28131cb0ef41Sopenharmony_ci } 28141cb0ef41Sopenharmony_ci} 28151cb0ef41Sopenharmony_ci 28161cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildClassProperty(ClassLiteral::Property* property) { 28171cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 28181cb0ef41Sopenharmony_ci Register key; 28191cb0ef41Sopenharmony_ci 28201cb0ef41Sopenharmony_ci // Private methods are not initialized in BuildClassProperty. 28211cb0ef41Sopenharmony_ci DCHECK_IMPLIES(property->is_private(), 28221cb0ef41Sopenharmony_ci property->kind() == ClassLiteral::Property::FIELD); 28231cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property->key()); 28241cb0ef41Sopenharmony_ci 28251cb0ef41Sopenharmony_ci bool is_literal_store = property->key()->IsPropertyName() && 28261cb0ef41Sopenharmony_ci !property->is_computed_name() && 28271cb0ef41Sopenharmony_ci !property->is_private(); 28281cb0ef41Sopenharmony_ci 28291cb0ef41Sopenharmony_ci if (!is_literal_store) { 28301cb0ef41Sopenharmony_ci key = register_allocator()->NewRegister(); 28311cb0ef41Sopenharmony_ci if (property->is_computed_name()) { 28321cb0ef41Sopenharmony_ci DCHECK_EQ(property->kind(), ClassLiteral::Property::FIELD); 28331cb0ef41Sopenharmony_ci DCHECK(!property->is_private()); 28341cb0ef41Sopenharmony_ci Variable* var = property->computed_name_var(); 28351cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(var); 28361cb0ef41Sopenharmony_ci // The computed name is already evaluated and stored in a variable at 28371cb0ef41Sopenharmony_ci // class definition time. 28381cb0ef41Sopenharmony_ci BuildVariableLoad(var, HoleCheckMode::kElided); 28391cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(key); 28401cb0ef41Sopenharmony_ci } else if (property->is_private()) { 28411cb0ef41Sopenharmony_ci Variable* private_name_var = property->private_name_var(); 28421cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(private_name_var); 28431cb0ef41Sopenharmony_ci BuildVariableLoad(private_name_var, HoleCheckMode::kElided); 28441cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(key); 28451cb0ef41Sopenharmony_ci } else { 28461cb0ef41Sopenharmony_ci VisitForRegisterValue(property->key(), key); 28471cb0ef41Sopenharmony_ci } 28481cb0ef41Sopenharmony_ci } 28491cb0ef41Sopenharmony_ci 28501cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(property->value()); 28511cb0ef41Sopenharmony_ci VisitForAccumulatorValue(property->value()); 28521cb0ef41Sopenharmony_ci 28531cb0ef41Sopenharmony_ci if (is_literal_store) { 28541cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddDefineNamedOwnICSlot(); 28551cb0ef41Sopenharmony_ci builder()->DefineNamedOwnProperty( 28561cb0ef41Sopenharmony_ci builder()->Receiver(), 28571cb0ef41Sopenharmony_ci property->key()->AsLiteral()->AsRawPropertyName(), 28581cb0ef41Sopenharmony_ci feedback_index(slot)); 28591cb0ef41Sopenharmony_ci } else { 28601cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddDefineKeyedOwnICSlot(); 28611cb0ef41Sopenharmony_ci builder()->DefineKeyedOwnProperty(builder()->Receiver(), key, 28621cb0ef41Sopenharmony_ci feedback_index(slot)); 28631cb0ef41Sopenharmony_ci } 28641cb0ef41Sopenharmony_ci} 28651cb0ef41Sopenharmony_ci 28661cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitInitializeClassMembersStatement( 28671cb0ef41Sopenharmony_ci InitializeClassMembersStatement* stmt) { 28681cb0ef41Sopenharmony_ci for (int i = 0; i < stmt->fields()->length(); i++) { 28691cb0ef41Sopenharmony_ci BuildClassProperty(stmt->fields()->at(i)); 28701cb0ef41Sopenharmony_ci } 28711cb0ef41Sopenharmony_ci} 28721cb0ef41Sopenharmony_ci 28731cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitInitializeClassStaticElementsStatement( 28741cb0ef41Sopenharmony_ci InitializeClassStaticElementsStatement* stmt) { 28751cb0ef41Sopenharmony_ci for (int i = 0; i < stmt->elements()->length(); i++) { 28761cb0ef41Sopenharmony_ci ClassLiteral::StaticElement* element = stmt->elements()->at(i); 28771cb0ef41Sopenharmony_ci switch (element->kind()) { 28781cb0ef41Sopenharmony_ci case ClassLiteral::StaticElement::PROPERTY: 28791cb0ef41Sopenharmony_ci BuildClassProperty(element->property()); 28801cb0ef41Sopenharmony_ci break; 28811cb0ef41Sopenharmony_ci case ClassLiteral::StaticElement::STATIC_BLOCK: 28821cb0ef41Sopenharmony_ci VisitBlock(element->static_block()); 28831cb0ef41Sopenharmony_ci break; 28841cb0ef41Sopenharmony_ci } 28851cb0ef41Sopenharmony_ci } 28861cb0ef41Sopenharmony_ci} 28871cb0ef41Sopenharmony_ci 28881cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildInvalidPropertyAccess(MessageTemplate tmpl, 28891cb0ef41Sopenharmony_ci Property* property) { 28901cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 28911cb0ef41Sopenharmony_ci const AstRawString* name = property->key()->AsVariableProxy()->raw_name(); 28921cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 28931cb0ef41Sopenharmony_ci builder() 28941cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromEnum(tmpl)) 28951cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[0]) 28961cb0ef41Sopenharmony_ci .LoadLiteral(name) 28971cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) 28981cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kNewTypeError, args) 28991cb0ef41Sopenharmony_ci .Throw(); 29001cb0ef41Sopenharmony_ci} 29011cb0ef41Sopenharmony_ci 29021cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildPrivateBrandInitialization(Register receiver, 29031cb0ef41Sopenharmony_ci Variable* brand) { 29041cb0ef41Sopenharmony_ci BuildVariableLoad(brand, HoleCheckMode::kElided); 29051cb0ef41Sopenharmony_ci int depth = execution_context()->ContextChainDepth(brand->scope()); 29061cb0ef41Sopenharmony_ci ContextScope* class_context = execution_context()->Previous(depth); 29071cb0ef41Sopenharmony_ci if (class_context) { 29081cb0ef41Sopenharmony_ci Register brand_reg = register_allocator()->NewRegister(); 29091cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddDefineKeyedOwnICSlot(); 29101cb0ef41Sopenharmony_ci builder() 29111cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(brand_reg) 29121cb0ef41Sopenharmony_ci .LoadAccumulatorWithRegister(class_context->reg()) 29131cb0ef41Sopenharmony_ci .DefineKeyedOwnProperty(receiver, brand_reg, feedback_index(slot)); 29141cb0ef41Sopenharmony_ci } else { 29151cb0ef41Sopenharmony_ci // We are in the slow case where super() is called from a nested 29161cb0ef41Sopenharmony_ci // arrow function or a eval(), so the class scope context isn't 29171cb0ef41Sopenharmony_ci // tracked in a context register in the stack, and we have to 29181cb0ef41Sopenharmony_ci // walk the context chain from the runtime to find it. 29191cb0ef41Sopenharmony_ci DCHECK_NE(info()->literal()->scope()->outer_scope(), brand->scope()); 29201cb0ef41Sopenharmony_ci RegisterList brand_args = register_allocator()->NewRegisterList(4); 29211cb0ef41Sopenharmony_ci builder() 29221cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(brand_args[1]) 29231cb0ef41Sopenharmony_ci .MoveRegister(receiver, brand_args[0]) 29241cb0ef41Sopenharmony_ci .MoveRegister(execution_context()->reg(), brand_args[2]) 29251cb0ef41Sopenharmony_ci .LoadLiteral(Smi::FromInt(depth)) 29261cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(brand_args[3]) 29271cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kAddPrivateBrand, brand_args); 29281cb0ef41Sopenharmony_ci } 29291cb0ef41Sopenharmony_ci} 29301cb0ef41Sopenharmony_ci 29311cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildInstanceMemberInitialization(Register constructor, 29321cb0ef41Sopenharmony_ci Register instance) { 29331cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(1); 29341cb0ef41Sopenharmony_ci Register initializer = register_allocator()->NewRegister(); 29351cb0ef41Sopenharmony_ci 29361cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddLoadICSlot(); 29371cb0ef41Sopenharmony_ci BytecodeLabel done; 29381cb0ef41Sopenharmony_ci 29391cb0ef41Sopenharmony_ci builder() 29401cb0ef41Sopenharmony_ci ->LoadClassFieldsInitializer(constructor, feedback_index(slot)) 29411cb0ef41Sopenharmony_ci // TODO(gsathya): This jump can be elided for the base 29421cb0ef41Sopenharmony_ci // constructor and derived constructor. This is only required 29431cb0ef41Sopenharmony_ci // when called from an arrow function. 29441cb0ef41Sopenharmony_ci .JumpIfUndefined(&done) 29451cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(initializer) 29461cb0ef41Sopenharmony_ci .MoveRegister(instance, args[0]) 29471cb0ef41Sopenharmony_ci .CallProperty(initializer, args, 29481cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot())) 29491cb0ef41Sopenharmony_ci .Bind(&done); 29501cb0ef41Sopenharmony_ci} 29511cb0ef41Sopenharmony_ci 29521cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNativeFunctionLiteral( 29531cb0ef41Sopenharmony_ci NativeFunctionLiteral* expr) { 29541cb0ef41Sopenharmony_ci size_t entry = builder()->AllocateDeferredConstantPoolEntry(); 29551cb0ef41Sopenharmony_ci int index = feedback_spec()->AddCreateClosureSlot(); 29561cb0ef41Sopenharmony_ci uint8_t flags = CreateClosureFlags::Encode(false, false, false); 29571cb0ef41Sopenharmony_ci builder()->CreateClosure(entry, index, flags); 29581cb0ef41Sopenharmony_ci native_function_literals_.push_back(std::make_pair(expr, entry)); 29591cb0ef41Sopenharmony_ci} 29601cb0ef41Sopenharmony_ci 29611cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitConditional(Conditional* expr) { 29621cb0ef41Sopenharmony_ci ConditionalControlFlowBuilder conditional_builder( 29631cb0ef41Sopenharmony_ci builder(), block_coverage_builder_, expr); 29641cb0ef41Sopenharmony_ci 29651cb0ef41Sopenharmony_ci if (expr->condition()->ToBooleanIsTrue()) { 29661cb0ef41Sopenharmony_ci // Generate then block unconditionally as always true. 29671cb0ef41Sopenharmony_ci conditional_builder.Then(); 29681cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->then_expression()); 29691cb0ef41Sopenharmony_ci } else if (expr->condition()->ToBooleanIsFalse()) { 29701cb0ef41Sopenharmony_ci // Generate else block unconditionally if it exists. 29711cb0ef41Sopenharmony_ci conditional_builder.Else(); 29721cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->else_expression()); 29731cb0ef41Sopenharmony_ci } else { 29741cb0ef41Sopenharmony_ci VisitForTest(expr->condition(), conditional_builder.then_labels(), 29751cb0ef41Sopenharmony_ci conditional_builder.else_labels(), TestFallthrough::kThen); 29761cb0ef41Sopenharmony_ci 29771cb0ef41Sopenharmony_ci conditional_builder.Then(); 29781cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->then_expression()); 29791cb0ef41Sopenharmony_ci conditional_builder.JumpToEnd(); 29801cb0ef41Sopenharmony_ci 29811cb0ef41Sopenharmony_ci conditional_builder.Else(); 29821cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->else_expression()); 29831cb0ef41Sopenharmony_ci } 29841cb0ef41Sopenharmony_ci} 29851cb0ef41Sopenharmony_ci 29861cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitLiteral(Literal* expr) { 29871cb0ef41Sopenharmony_ci if (execution_result()->IsEffect()) return; 29881cb0ef41Sopenharmony_ci switch (expr->type()) { 29891cb0ef41Sopenharmony_ci case Literal::kSmi: 29901cb0ef41Sopenharmony_ci builder()->LoadLiteral(expr->AsSmiLiteral()); 29911cb0ef41Sopenharmony_ci break; 29921cb0ef41Sopenharmony_ci case Literal::kHeapNumber: 29931cb0ef41Sopenharmony_ci builder()->LoadLiteral(expr->AsNumber()); 29941cb0ef41Sopenharmony_ci break; 29951cb0ef41Sopenharmony_ci case Literal::kUndefined: 29961cb0ef41Sopenharmony_ci builder()->LoadUndefined(); 29971cb0ef41Sopenharmony_ci break; 29981cb0ef41Sopenharmony_ci case Literal::kBoolean: 29991cb0ef41Sopenharmony_ci builder()->LoadBoolean(expr->ToBooleanIsTrue()); 30001cb0ef41Sopenharmony_ci execution_result()->SetResultIsBoolean(); 30011cb0ef41Sopenharmony_ci break; 30021cb0ef41Sopenharmony_ci case Literal::kNull: 30031cb0ef41Sopenharmony_ci builder()->LoadNull(); 30041cb0ef41Sopenharmony_ci break; 30051cb0ef41Sopenharmony_ci case Literal::kTheHole: 30061cb0ef41Sopenharmony_ci builder()->LoadTheHole(); 30071cb0ef41Sopenharmony_ci break; 30081cb0ef41Sopenharmony_ci case Literal::kString: 30091cb0ef41Sopenharmony_ci builder()->LoadLiteral(expr->AsRawString()); 30101cb0ef41Sopenharmony_ci execution_result()->SetResultIsString(); 30111cb0ef41Sopenharmony_ci break; 30121cb0ef41Sopenharmony_ci case Literal::kBigInt: 30131cb0ef41Sopenharmony_ci builder()->LoadLiteral(expr->AsBigInt()); 30141cb0ef41Sopenharmony_ci break; 30151cb0ef41Sopenharmony_ci } 30161cb0ef41Sopenharmony_ci} 30171cb0ef41Sopenharmony_ci 30181cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { 30191cb0ef41Sopenharmony_ci // Materialize a regular expression literal. 30201cb0ef41Sopenharmony_ci builder()->CreateRegExpLiteral( 30211cb0ef41Sopenharmony_ci expr->raw_pattern(), feedback_index(feedback_spec()->AddLiteralSlot()), 30221cb0ef41Sopenharmony_ci expr->flags()); 30231cb0ef41Sopenharmony_ci} 30241cb0ef41Sopenharmony_ci 30251cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildCreateObjectLiteral(Register literal, 30261cb0ef41Sopenharmony_ci uint8_t flags, size_t entry) { 30271cb0ef41Sopenharmony_ci // TODO(cbruni): Directly generate runtime call for literals we cannot 30281cb0ef41Sopenharmony_ci // optimize once the CreateShallowObjectLiteral stub is in sync with the TF 30291cb0ef41Sopenharmony_ci // optimizations. 30301cb0ef41Sopenharmony_ci int literal_index = feedback_index(feedback_spec()->AddLiteralSlot()); 30311cb0ef41Sopenharmony_ci builder() 30321cb0ef41Sopenharmony_ci ->CreateObjectLiteral(entry, literal_index, flags) 30331cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(literal); 30341cb0ef41Sopenharmony_ci} 30351cb0ef41Sopenharmony_ci 30361cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { 30371cb0ef41Sopenharmony_ci expr->builder()->InitDepthAndFlags(); 30381cb0ef41Sopenharmony_ci 30391cb0ef41Sopenharmony_ci // Fast path for the empty object literal which doesn't need an 30401cb0ef41Sopenharmony_ci // AllocationSite. 30411cb0ef41Sopenharmony_ci if (expr->builder()->IsEmptyObjectLiteral()) { 30421cb0ef41Sopenharmony_ci DCHECK(expr->builder()->IsFastCloningSupported()); 30431cb0ef41Sopenharmony_ci builder()->CreateEmptyObjectLiteral(); 30441cb0ef41Sopenharmony_ci return; 30451cb0ef41Sopenharmony_ci } 30461cb0ef41Sopenharmony_ci 30471cb0ef41Sopenharmony_ci Variable* home_object = expr->home_object(); 30481cb0ef41Sopenharmony_ci if (home_object != nullptr) { 30491cb0ef41Sopenharmony_ci DCHECK(home_object->is_used()); 30501cb0ef41Sopenharmony_ci DCHECK(home_object->IsContextSlot()); 30511cb0ef41Sopenharmony_ci } 30521cb0ef41Sopenharmony_ci MultipleEntryBlockContextScope object_literal_context_scope( 30531cb0ef41Sopenharmony_ci this, home_object ? home_object->scope() : nullptr); 30541cb0ef41Sopenharmony_ci 30551cb0ef41Sopenharmony_ci // Deep-copy the literal boilerplate. 30561cb0ef41Sopenharmony_ci uint8_t flags = CreateObjectLiteralFlags::Encode( 30571cb0ef41Sopenharmony_ci expr->builder()->ComputeFlags(), 30581cb0ef41Sopenharmony_ci expr->builder()->IsFastCloningSupported()); 30591cb0ef41Sopenharmony_ci 30601cb0ef41Sopenharmony_ci Register literal = register_allocator()->NewRegister(); 30611cb0ef41Sopenharmony_ci 30621cb0ef41Sopenharmony_ci // Create literal object. 30631cb0ef41Sopenharmony_ci int property_index = 0; 30641cb0ef41Sopenharmony_ci bool clone_object_spread = 30651cb0ef41Sopenharmony_ci expr->properties()->first()->kind() == ObjectLiteral::Property::SPREAD; 30661cb0ef41Sopenharmony_ci if (clone_object_spread) { 30671cb0ef41Sopenharmony_ci // Avoid the slow path for spreads in the following common cases: 30681cb0ef41Sopenharmony_ci // 1) `let obj = { ...source }` 30691cb0ef41Sopenharmony_ci // 2) `let obj = { ...source, override: 1 }` 30701cb0ef41Sopenharmony_ci // 3) `let obj = { ...source, ...overrides }` 30711cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 30721cb0ef41Sopenharmony_ci Expression* property = expr->properties()->first()->value(); 30731cb0ef41Sopenharmony_ci Register from_value = VisitForRegisterValue(property); 30741cb0ef41Sopenharmony_ci int clone_index = feedback_index(feedback_spec()->AddCloneObjectSlot()); 30751cb0ef41Sopenharmony_ci builder()->CloneObject(from_value, flags, clone_index); 30761cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(literal); 30771cb0ef41Sopenharmony_ci property_index++; 30781cb0ef41Sopenharmony_ci } else { 30791cb0ef41Sopenharmony_ci size_t entry; 30801cb0ef41Sopenharmony_ci // If constant properties is an empty fixed array, use a cached empty fixed 30811cb0ef41Sopenharmony_ci // array to ensure it's only added to the constant pool once. 30821cb0ef41Sopenharmony_ci if (expr->builder()->properties_count() == 0) { 30831cb0ef41Sopenharmony_ci entry = builder()->EmptyObjectBoilerplateDescriptionConstantPoolEntry(); 30841cb0ef41Sopenharmony_ci } else { 30851cb0ef41Sopenharmony_ci entry = builder()->AllocateDeferredConstantPoolEntry(); 30861cb0ef41Sopenharmony_ci object_literals_.push_back(std::make_pair(expr->builder(), entry)); 30871cb0ef41Sopenharmony_ci } 30881cb0ef41Sopenharmony_ci BuildCreateObjectLiteral(literal, flags, entry); 30891cb0ef41Sopenharmony_ci } 30901cb0ef41Sopenharmony_ci 30911cb0ef41Sopenharmony_ci // Store computed values into the literal. 30921cb0ef41Sopenharmony_ci AccessorTable<ObjectLiteral::Property> accessor_table(zone()); 30931cb0ef41Sopenharmony_ci for (; property_index < expr->properties()->length(); property_index++) { 30941cb0ef41Sopenharmony_ci ObjectLiteral::Property* property = expr->properties()->at(property_index); 30951cb0ef41Sopenharmony_ci if (property->is_computed_name()) break; 30961cb0ef41Sopenharmony_ci if (!clone_object_spread && property->IsCompileTimeValue()) continue; 30971cb0ef41Sopenharmony_ci 30981cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 30991cb0ef41Sopenharmony_ci Literal* key = property->key()->AsLiteral(); 31001cb0ef41Sopenharmony_ci switch (property->kind()) { 31011cb0ef41Sopenharmony_ci case ObjectLiteral::Property::SPREAD: 31021cb0ef41Sopenharmony_ci UNREACHABLE(); 31031cb0ef41Sopenharmony_ci case ObjectLiteral::Property::CONSTANT: 31041cb0ef41Sopenharmony_ci case ObjectLiteral::Property::MATERIALIZED_LITERAL: 31051cb0ef41Sopenharmony_ci DCHECK(clone_object_spread || !property->value()->IsCompileTimeValue()); 31061cb0ef41Sopenharmony_ci V8_FALLTHROUGH; 31071cb0ef41Sopenharmony_ci case ObjectLiteral::Property::COMPUTED: { 31081cb0ef41Sopenharmony_ci // It is safe to use [[Put]] here because the boilerplate already 31091cb0ef41Sopenharmony_ci // contains computed properties with an uninitialized value. 31101cb0ef41Sopenharmony_ci Register key_reg; 31111cb0ef41Sopenharmony_ci if (key->IsStringLiteral()) { 31121cb0ef41Sopenharmony_ci DCHECK(key->IsPropertyName()); 31131cb0ef41Sopenharmony_ci } else { 31141cb0ef41Sopenharmony_ci key_reg = register_allocator()->NewRegister(); 31151cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property->key()); 31161cb0ef41Sopenharmony_ci VisitForRegisterValue(property->key(), key_reg); 31171cb0ef41Sopenharmony_ci } 31181cb0ef41Sopenharmony_ci 31191cb0ef41Sopenharmony_ci object_literal_context_scope.SetEnteredIf( 31201cb0ef41Sopenharmony_ci property->value()->IsConciseMethodDefinition()); 31211cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property->value()); 31221cb0ef41Sopenharmony_ci 31231cb0ef41Sopenharmony_ci if (property->emit_store()) { 31241cb0ef41Sopenharmony_ci VisitForAccumulatorValue(property->value()); 31251cb0ef41Sopenharmony_ci if (key->IsStringLiteral()) { 31261cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddDefineNamedOwnICSlot(); 31271cb0ef41Sopenharmony_ci builder()->DefineNamedOwnProperty(literal, key->AsRawPropertyName(), 31281cb0ef41Sopenharmony_ci feedback_index(slot)); 31291cb0ef41Sopenharmony_ci } else { 31301cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddDefineKeyedOwnICSlot(); 31311cb0ef41Sopenharmony_ci builder()->DefineKeyedOwnProperty(literal, key_reg, 31321cb0ef41Sopenharmony_ci feedback_index(slot)); 31331cb0ef41Sopenharmony_ci } 31341cb0ef41Sopenharmony_ci } else { 31351cb0ef41Sopenharmony_ci VisitForEffect(property->value()); 31361cb0ef41Sopenharmony_ci } 31371cb0ef41Sopenharmony_ci break; 31381cb0ef41Sopenharmony_ci } 31391cb0ef41Sopenharmony_ci case ObjectLiteral::Property::PROTOTYPE: { 31401cb0ef41Sopenharmony_ci // __proto__:null is handled by CreateObjectLiteral. 31411cb0ef41Sopenharmony_ci if (property->IsNullPrototype()) break; 31421cb0ef41Sopenharmony_ci DCHECK(property->emit_store()); 31431cb0ef41Sopenharmony_ci DCHECK(!property->NeedsSetFunctionName()); 31441cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 31451cb0ef41Sopenharmony_ci builder()->MoveRegister(literal, args[0]); 31461cb0ef41Sopenharmony_ci object_literal_context_scope.SetEnteredIf(false); 31471cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property->value()); 31481cb0ef41Sopenharmony_ci VisitForRegisterValue(property->value(), args[1]); 31491cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kInternalSetPrototype, args); 31501cb0ef41Sopenharmony_ci break; 31511cb0ef41Sopenharmony_ci } 31521cb0ef41Sopenharmony_ci case ObjectLiteral::Property::GETTER: 31531cb0ef41Sopenharmony_ci if (property->emit_store()) { 31541cb0ef41Sopenharmony_ci accessor_table.LookupOrInsert(key)->getter = property; 31551cb0ef41Sopenharmony_ci } 31561cb0ef41Sopenharmony_ci break; 31571cb0ef41Sopenharmony_ci case ObjectLiteral::Property::SETTER: 31581cb0ef41Sopenharmony_ci if (property->emit_store()) { 31591cb0ef41Sopenharmony_ci accessor_table.LookupOrInsert(key)->setter = property; 31601cb0ef41Sopenharmony_ci } 31611cb0ef41Sopenharmony_ci break; 31621cb0ef41Sopenharmony_ci } 31631cb0ef41Sopenharmony_ci } 31641cb0ef41Sopenharmony_ci 31651cb0ef41Sopenharmony_ci // Define accessors, using only a single call to the runtime for each pair 31661cb0ef41Sopenharmony_ci // of corresponding getters and setters. 31671cb0ef41Sopenharmony_ci object_literal_context_scope.SetEnteredIf(true); 31681cb0ef41Sopenharmony_ci for (auto accessors : accessor_table.ordered_accessors()) { 31691cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 31701cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(5); 31711cb0ef41Sopenharmony_ci builder()->MoveRegister(literal, args[0]); 31721cb0ef41Sopenharmony_ci VisitForRegisterValue(accessors.first, args[1]); 31731cb0ef41Sopenharmony_ci VisitLiteralAccessor(accessors.second->getter, args[2]); 31741cb0ef41Sopenharmony_ci VisitLiteralAccessor(accessors.second->setter, args[3]); 31751cb0ef41Sopenharmony_ci builder() 31761cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromInt(NONE)) 31771cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[4]) 31781cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args); 31791cb0ef41Sopenharmony_ci } 31801cb0ef41Sopenharmony_ci 31811cb0ef41Sopenharmony_ci // Object literals have two parts. The "static" part on the left contains no 31821cb0ef41Sopenharmony_ci // computed property names, and so we can compute its map ahead of time; see 31831cb0ef41Sopenharmony_ci // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts 31841cb0ef41Sopenharmony_ci // with the first computed property name and continues with all properties to 31851cb0ef41Sopenharmony_ci // its right. All the code from above initializes the static component of the 31861cb0ef41Sopenharmony_ci // object literal, and arranges for the map of the result to reflect the 31871cb0ef41Sopenharmony_ci // static order in which the keys appear. For the dynamic properties, we 31881cb0ef41Sopenharmony_ci // compile them into a series of "SetOwnProperty" runtime calls. This will 31891cb0ef41Sopenharmony_ci // preserve insertion order. 31901cb0ef41Sopenharmony_ci for (; property_index < expr->properties()->length(); property_index++) { 31911cb0ef41Sopenharmony_ci ObjectLiteral::Property* property = expr->properties()->at(property_index); 31921cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 31931cb0ef41Sopenharmony_ci 31941cb0ef41Sopenharmony_ci bool should_be_in_object_literal_scope = 31951cb0ef41Sopenharmony_ci (property->value()->IsConciseMethodDefinition() || 31961cb0ef41Sopenharmony_ci property->value()->IsAccessorFunctionDefinition()); 31971cb0ef41Sopenharmony_ci 31981cb0ef41Sopenharmony_ci if (property->IsPrototype()) { 31991cb0ef41Sopenharmony_ci // __proto__:null is handled by CreateObjectLiteral. 32001cb0ef41Sopenharmony_ci if (property->IsNullPrototype()) continue; 32011cb0ef41Sopenharmony_ci DCHECK(property->emit_store()); 32021cb0ef41Sopenharmony_ci DCHECK(!property->NeedsSetFunctionName()); 32031cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 32041cb0ef41Sopenharmony_ci builder()->MoveRegister(literal, args[0]); 32051cb0ef41Sopenharmony_ci 32061cb0ef41Sopenharmony_ci DCHECK(!should_be_in_object_literal_scope); 32071cb0ef41Sopenharmony_ci object_literal_context_scope.SetEnteredIf(false); 32081cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property->value()); 32091cb0ef41Sopenharmony_ci VisitForRegisterValue(property->value(), args[1]); 32101cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kInternalSetPrototype, args); 32111cb0ef41Sopenharmony_ci continue; 32121cb0ef41Sopenharmony_ci } 32131cb0ef41Sopenharmony_ci 32141cb0ef41Sopenharmony_ci switch (property->kind()) { 32151cb0ef41Sopenharmony_ci case ObjectLiteral::Property::CONSTANT: 32161cb0ef41Sopenharmony_ci case ObjectLiteral::Property::COMPUTED: 32171cb0ef41Sopenharmony_ci case ObjectLiteral::Property::MATERIALIZED_LITERAL: { 32181cb0ef41Sopenharmony_ci // Computed property keys don't belong to the object literal scope (even 32191cb0ef41Sopenharmony_ci // if they're syntactically inside it). 32201cb0ef41Sopenharmony_ci if (property->is_computed_name()) { 32211cb0ef41Sopenharmony_ci object_literal_context_scope.SetEnteredIf(false); 32221cb0ef41Sopenharmony_ci } 32231cb0ef41Sopenharmony_ci Register key = register_allocator()->NewRegister(); 32241cb0ef41Sopenharmony_ci BuildLoadPropertyKey(property, key); 32251cb0ef41Sopenharmony_ci 32261cb0ef41Sopenharmony_ci object_literal_context_scope.SetEnteredIf( 32271cb0ef41Sopenharmony_ci should_be_in_object_literal_scope); 32281cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property->value()); 32291cb0ef41Sopenharmony_ci Register value; 32301cb0ef41Sopenharmony_ci 32311cb0ef41Sopenharmony_ci // Static class fields require the name property to be set on 32321cb0ef41Sopenharmony_ci // the class, meaning we can't wait until the 32331cb0ef41Sopenharmony_ci // DefineKeyedOwnPropertyInLiteral call later to set the name. 32341cb0ef41Sopenharmony_ci if (property->value()->IsClassLiteral() && 32351cb0ef41Sopenharmony_ci property->value()->AsClassLiteral()->static_initializer() != 32361cb0ef41Sopenharmony_ci nullptr) { 32371cb0ef41Sopenharmony_ci value = register_allocator()->NewRegister(); 32381cb0ef41Sopenharmony_ci VisitClassLiteral(property->value()->AsClassLiteral(), key); 32391cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(value); 32401cb0ef41Sopenharmony_ci } else { 32411cb0ef41Sopenharmony_ci value = VisitForRegisterValue(property->value()); 32421cb0ef41Sopenharmony_ci } 32431cb0ef41Sopenharmony_ci 32441cb0ef41Sopenharmony_ci DefineKeyedOwnPropertyInLiteralFlags data_property_flags = 32451cb0ef41Sopenharmony_ci DefineKeyedOwnPropertyInLiteralFlag::kNoFlags; 32461cb0ef41Sopenharmony_ci if (property->NeedsSetFunctionName()) { 32471cb0ef41Sopenharmony_ci data_property_flags |= 32481cb0ef41Sopenharmony_ci DefineKeyedOwnPropertyInLiteralFlag::kSetFunctionName; 32491cb0ef41Sopenharmony_ci } 32501cb0ef41Sopenharmony_ci 32511cb0ef41Sopenharmony_ci FeedbackSlot slot = 32521cb0ef41Sopenharmony_ci feedback_spec()->AddDefineKeyedOwnPropertyInLiteralICSlot(); 32531cb0ef41Sopenharmony_ci builder() 32541cb0ef41Sopenharmony_ci ->LoadAccumulatorWithRegister(value) 32551cb0ef41Sopenharmony_ci .DefineKeyedOwnPropertyInLiteral(literal, key, data_property_flags, 32561cb0ef41Sopenharmony_ci feedback_index(slot)); 32571cb0ef41Sopenharmony_ci break; 32581cb0ef41Sopenharmony_ci } 32591cb0ef41Sopenharmony_ci case ObjectLiteral::Property::GETTER: 32601cb0ef41Sopenharmony_ci case ObjectLiteral::Property::SETTER: { 32611cb0ef41Sopenharmony_ci // Computed property keys don't belong to the object literal scope (even 32621cb0ef41Sopenharmony_ci // if they're syntactically inside it). 32631cb0ef41Sopenharmony_ci if (property->is_computed_name()) { 32641cb0ef41Sopenharmony_ci object_literal_context_scope.SetEnteredIf(false); 32651cb0ef41Sopenharmony_ci } 32661cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(4); 32671cb0ef41Sopenharmony_ci builder()->MoveRegister(literal, args[0]); 32681cb0ef41Sopenharmony_ci BuildLoadPropertyKey(property, args[1]); 32691cb0ef41Sopenharmony_ci 32701cb0ef41Sopenharmony_ci DCHECK(should_be_in_object_literal_scope); 32711cb0ef41Sopenharmony_ci object_literal_context_scope.SetEnteredIf(true); 32721cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property->value()); 32731cb0ef41Sopenharmony_ci VisitForRegisterValue(property->value(), args[2]); 32741cb0ef41Sopenharmony_ci builder() 32751cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromInt(NONE)) 32761cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[3]); 32771cb0ef41Sopenharmony_ci Runtime::FunctionId function_id = 32781cb0ef41Sopenharmony_ci property->kind() == ObjectLiteral::Property::GETTER 32791cb0ef41Sopenharmony_ci ? Runtime::kDefineGetterPropertyUnchecked 32801cb0ef41Sopenharmony_ci : Runtime::kDefineSetterPropertyUnchecked; 32811cb0ef41Sopenharmony_ci builder()->CallRuntime(function_id, args); 32821cb0ef41Sopenharmony_ci break; 32831cb0ef41Sopenharmony_ci } 32841cb0ef41Sopenharmony_ci case ObjectLiteral::Property::SPREAD: { 32851cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 32861cb0ef41Sopenharmony_ci builder()->MoveRegister(literal, args[0]); 32871cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property->value()); 32881cb0ef41Sopenharmony_ci object_literal_context_scope.SetEnteredIf(false); 32891cb0ef41Sopenharmony_ci VisitForRegisterValue(property->value(), args[1]); 32901cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kInlineCopyDataProperties, args); 32911cb0ef41Sopenharmony_ci break; 32921cb0ef41Sopenharmony_ci } 32931cb0ef41Sopenharmony_ci case ObjectLiteral::Property::PROTOTYPE: 32941cb0ef41Sopenharmony_ci UNREACHABLE(); // Handled specially above. 32951cb0ef41Sopenharmony_ci } 32961cb0ef41Sopenharmony_ci } 32971cb0ef41Sopenharmony_ci 32981cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(literal); 32991cb0ef41Sopenharmony_ci if (home_object != nullptr) { 33001cb0ef41Sopenharmony_ci object_literal_context_scope.SetEnteredIf(true); 33011cb0ef41Sopenharmony_ci BuildVariableAssignment(home_object, Token::INIT, HoleCheckMode::kElided); 33021cb0ef41Sopenharmony_ci } 33031cb0ef41Sopenharmony_ci} 33041cb0ef41Sopenharmony_ci 33051cb0ef41Sopenharmony_ci// Fill an array with values from an iterator, starting at a given index. It is 33061cb0ef41Sopenharmony_ci// guaranteed that the loop will only terminate if the iterator is exhausted, or 33071cb0ef41Sopenharmony_ci// if one of iterator.next(), value.done, or value.value fail. 33081cb0ef41Sopenharmony_ci// 33091cb0ef41Sopenharmony_ci// In pseudocode: 33101cb0ef41Sopenharmony_ci// 33111cb0ef41Sopenharmony_ci// loop { 33121cb0ef41Sopenharmony_ci// value = iterator.next() 33131cb0ef41Sopenharmony_ci// if (value.done) break; 33141cb0ef41Sopenharmony_ci// value = value.value 33151cb0ef41Sopenharmony_ci// array[index++] = value 33161cb0ef41Sopenharmony_ci// } 33171cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildFillArrayWithIterator( 33181cb0ef41Sopenharmony_ci IteratorRecord iterator, Register array, Register index, Register value, 33191cb0ef41Sopenharmony_ci FeedbackSlot next_value_slot, FeedbackSlot next_done_slot, 33201cb0ef41Sopenharmony_ci FeedbackSlot index_slot, FeedbackSlot element_slot) { 33211cb0ef41Sopenharmony_ci DCHECK(array.is_valid()); 33221cb0ef41Sopenharmony_ci DCHECK(index.is_valid()); 33231cb0ef41Sopenharmony_ci DCHECK(value.is_valid()); 33241cb0ef41Sopenharmony_ci 33251cb0ef41Sopenharmony_ci LoopBuilder loop_builder(builder(), nullptr, nullptr); 33261cb0ef41Sopenharmony_ci LoopScope loop_scope(this, &loop_builder); 33271cb0ef41Sopenharmony_ci 33281cb0ef41Sopenharmony_ci // Call the iterator's .next() method. Break from the loop if the `done` 33291cb0ef41Sopenharmony_ci // property is truthy, otherwise load the value from the iterator result and 33301cb0ef41Sopenharmony_ci // append the argument. 33311cb0ef41Sopenharmony_ci BuildIteratorNext(iterator, value); 33321cb0ef41Sopenharmony_ci builder()->LoadNamedProperty( 33331cb0ef41Sopenharmony_ci value, ast_string_constants()->done_string(), 33341cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLoadICSlot())); 33351cb0ef41Sopenharmony_ci loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean); 33361cb0ef41Sopenharmony_ci 33371cb0ef41Sopenharmony_ci loop_builder.LoopBody(); 33381cb0ef41Sopenharmony_ci builder() 33391cb0ef41Sopenharmony_ci // value = value.value 33401cb0ef41Sopenharmony_ci ->LoadNamedProperty(value, ast_string_constants()->value_string(), 33411cb0ef41Sopenharmony_ci feedback_index(next_value_slot)) 33421cb0ef41Sopenharmony_ci // array[index] = value 33431cb0ef41Sopenharmony_ci .StoreInArrayLiteral(array, index, feedback_index(element_slot)) 33441cb0ef41Sopenharmony_ci // index++ 33451cb0ef41Sopenharmony_ci .LoadAccumulatorWithRegister(index) 33461cb0ef41Sopenharmony_ci .UnaryOperation(Token::INC, feedback_index(index_slot)) 33471cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(index); 33481cb0ef41Sopenharmony_ci loop_builder.BindContinueTarget(); 33491cb0ef41Sopenharmony_ci} 33501cb0ef41Sopenharmony_ci 33511cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildCreateArrayLiteral( 33521cb0ef41Sopenharmony_ci const ZonePtrList<Expression>* elements, ArrayLiteral* expr) { 33531cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 33541cb0ef41Sopenharmony_ci Register index = register_allocator()->NewRegister(); 33551cb0ef41Sopenharmony_ci Register array = register_allocator()->NewRegister(); 33561cb0ef41Sopenharmony_ci SharedFeedbackSlot element_slot(feedback_spec(), 33571cb0ef41Sopenharmony_ci FeedbackSlotKind::kStoreInArrayLiteral); 33581cb0ef41Sopenharmony_ci ZonePtrList<Expression>::const_iterator current = elements->begin(); 33591cb0ef41Sopenharmony_ci ZonePtrList<Expression>::const_iterator end = elements->end(); 33601cb0ef41Sopenharmony_ci bool is_empty = elements->is_empty(); 33611cb0ef41Sopenharmony_ci 33621cb0ef41Sopenharmony_ci if (!is_empty && (*current)->IsSpread()) { 33631cb0ef41Sopenharmony_ci // If we have a leading spread, use CreateArrayFromIterable to create 33641cb0ef41Sopenharmony_ci // an array from it and then add the remaining components to that array. 33651cb0ef41Sopenharmony_ci VisitForAccumulatorValue(*current); 33661cb0ef41Sopenharmony_ci builder()->SetExpressionPosition((*current)->AsSpread()->expression()); 33671cb0ef41Sopenharmony_ci builder()->CreateArrayFromIterable().StoreAccumulatorInRegister(array); 33681cb0ef41Sopenharmony_ci 33691cb0ef41Sopenharmony_ci if (++current != end) { 33701cb0ef41Sopenharmony_ci // If there are remaning elements, prepare the index register that is 33711cb0ef41Sopenharmony_ci // used for adding those elements. The next index is the length of the 33721cb0ef41Sopenharmony_ci // newly created array. 33731cb0ef41Sopenharmony_ci auto length = ast_string_constants()->length_string(); 33741cb0ef41Sopenharmony_ci int length_load_slot = feedback_index(feedback_spec()->AddLoadICSlot()); 33751cb0ef41Sopenharmony_ci builder() 33761cb0ef41Sopenharmony_ci ->LoadNamedProperty(array, length, length_load_slot) 33771cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(index); 33781cb0ef41Sopenharmony_ci } 33791cb0ef41Sopenharmony_ci } else { 33801cb0ef41Sopenharmony_ci // There are some elements before the first (if any) spread, and we can 33811cb0ef41Sopenharmony_ci // use a boilerplate when creating the initial array from those elements. 33821cb0ef41Sopenharmony_ci 33831cb0ef41Sopenharmony_ci // First, allocate a constant pool entry for the boilerplate that will 33841cb0ef41Sopenharmony_ci // be created during finalization, and will contain all the constant 33851cb0ef41Sopenharmony_ci // elements before the first spread. This also handle the empty array case 33861cb0ef41Sopenharmony_ci // and one-shot optimization. 33871cb0ef41Sopenharmony_ci 33881cb0ef41Sopenharmony_ci ArrayLiteralBoilerplateBuilder* array_literal_builder = nullptr; 33891cb0ef41Sopenharmony_ci if (expr != nullptr) { 33901cb0ef41Sopenharmony_ci array_literal_builder = expr->builder(); 33911cb0ef41Sopenharmony_ci } else { 33921cb0ef41Sopenharmony_ci DCHECK(!elements->is_empty()); 33931cb0ef41Sopenharmony_ci 33941cb0ef41Sopenharmony_ci // get first_spread_index 33951cb0ef41Sopenharmony_ci int first_spread_index = -1; 33961cb0ef41Sopenharmony_ci for (auto iter = elements->begin(); iter != elements->end(); iter++) { 33971cb0ef41Sopenharmony_ci if ((*iter)->IsSpread()) { 33981cb0ef41Sopenharmony_ci first_spread_index = static_cast<int>(iter - elements->begin()); 33991cb0ef41Sopenharmony_ci break; 34001cb0ef41Sopenharmony_ci } 34011cb0ef41Sopenharmony_ci } 34021cb0ef41Sopenharmony_ci 34031cb0ef41Sopenharmony_ci array_literal_builder = zone()->New<ArrayLiteralBoilerplateBuilder>( 34041cb0ef41Sopenharmony_ci elements, first_spread_index); 34051cb0ef41Sopenharmony_ci array_literal_builder->InitDepthAndFlags(); 34061cb0ef41Sopenharmony_ci } 34071cb0ef41Sopenharmony_ci 34081cb0ef41Sopenharmony_ci DCHECK(array_literal_builder != nullptr); 34091cb0ef41Sopenharmony_ci uint8_t flags = CreateArrayLiteralFlags::Encode( 34101cb0ef41Sopenharmony_ci array_literal_builder->IsFastCloningSupported(), 34111cb0ef41Sopenharmony_ci array_literal_builder->ComputeFlags()); 34121cb0ef41Sopenharmony_ci if (is_empty) { 34131cb0ef41Sopenharmony_ci // Empty array literal fast-path. 34141cb0ef41Sopenharmony_ci int literal_index = feedback_index(feedback_spec()->AddLiteralSlot()); 34151cb0ef41Sopenharmony_ci DCHECK(array_literal_builder->IsFastCloningSupported()); 34161cb0ef41Sopenharmony_ci builder()->CreateEmptyArrayLiteral(literal_index); 34171cb0ef41Sopenharmony_ci } else { 34181cb0ef41Sopenharmony_ci // Create array literal from boilerplate. 34191cb0ef41Sopenharmony_ci size_t entry = builder()->AllocateDeferredConstantPoolEntry(); 34201cb0ef41Sopenharmony_ci array_literals_.push_back(std::make_pair(array_literal_builder, entry)); 34211cb0ef41Sopenharmony_ci int literal_index = feedback_index(feedback_spec()->AddLiteralSlot()); 34221cb0ef41Sopenharmony_ci builder()->CreateArrayLiteral(entry, literal_index, flags); 34231cb0ef41Sopenharmony_ci } 34241cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(array); 34251cb0ef41Sopenharmony_ci 34261cb0ef41Sopenharmony_ci ZonePtrList<Expression>::const_iterator first_spread_or_end = 34271cb0ef41Sopenharmony_ci array_literal_builder->first_spread_index() >= 0 34281cb0ef41Sopenharmony_ci ? current + array_literal_builder->first_spread_index() 34291cb0ef41Sopenharmony_ci : end; 34301cb0ef41Sopenharmony_ci 34311cb0ef41Sopenharmony_ci // Insert the missing non-constant elements, up until the first spread 34321cb0ef41Sopenharmony_ci // index, into the initial array (the remaining elements will be inserted 34331cb0ef41Sopenharmony_ci // below). 34341cb0ef41Sopenharmony_ci DCHECK_EQ(current, elements->begin()); 34351cb0ef41Sopenharmony_ci int array_index = 0; 34361cb0ef41Sopenharmony_ci for (; current != first_spread_or_end; ++current, array_index++) { 34371cb0ef41Sopenharmony_ci Expression* subexpr = *current; 34381cb0ef41Sopenharmony_ci DCHECK(!subexpr->IsSpread()); 34391cb0ef41Sopenharmony_ci // Skip the constants. 34401cb0ef41Sopenharmony_ci if (subexpr->IsCompileTimeValue()) continue; 34411cb0ef41Sopenharmony_ci 34421cb0ef41Sopenharmony_ci builder() 34431cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromInt(array_index)) 34441cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(index); 34451cb0ef41Sopenharmony_ci VisitForAccumulatorValue(subexpr); 34461cb0ef41Sopenharmony_ci builder()->StoreInArrayLiteral(array, index, 34471cb0ef41Sopenharmony_ci feedback_index(element_slot.Get())); 34481cb0ef41Sopenharmony_ci } 34491cb0ef41Sopenharmony_ci 34501cb0ef41Sopenharmony_ci if (current != end) { 34511cb0ef41Sopenharmony_ci // If there are remaining elements, prepare the index register 34521cb0ef41Sopenharmony_ci // to store the next element, which comes from the first spread. 34531cb0ef41Sopenharmony_ci builder() 34541cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromInt(array_index)) 34551cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(index); 34561cb0ef41Sopenharmony_ci } 34571cb0ef41Sopenharmony_ci } 34581cb0ef41Sopenharmony_ci 34591cb0ef41Sopenharmony_ci // Now build insertions for the remaining elements from current to end. 34601cb0ef41Sopenharmony_ci SharedFeedbackSlot index_slot(feedback_spec(), FeedbackSlotKind::kBinaryOp); 34611cb0ef41Sopenharmony_ci SharedFeedbackSlot length_slot( 34621cb0ef41Sopenharmony_ci feedback_spec(), feedback_spec()->GetStoreICSlot(LanguageMode::kStrict)); 34631cb0ef41Sopenharmony_ci for (; current != end; ++current) { 34641cb0ef41Sopenharmony_ci Expression* subexpr = *current; 34651cb0ef41Sopenharmony_ci if (subexpr->IsSpread()) { 34661cb0ef41Sopenharmony_ci RegisterAllocationScope scope(this); 34671cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition( 34681cb0ef41Sopenharmony_ci subexpr->AsSpread()->expression()); 34691cb0ef41Sopenharmony_ci VisitForAccumulatorValue(subexpr->AsSpread()->expression()); 34701cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(subexpr->AsSpread()->expression()); 34711cb0ef41Sopenharmony_ci IteratorRecord iterator = BuildGetIteratorRecord(IteratorType::kNormal); 34721cb0ef41Sopenharmony_ci 34731cb0ef41Sopenharmony_ci Register value = register_allocator()->NewRegister(); 34741cb0ef41Sopenharmony_ci FeedbackSlot next_value_load_slot = feedback_spec()->AddLoadICSlot(); 34751cb0ef41Sopenharmony_ci FeedbackSlot next_done_load_slot = feedback_spec()->AddLoadICSlot(); 34761cb0ef41Sopenharmony_ci FeedbackSlot real_index_slot = index_slot.Get(); 34771cb0ef41Sopenharmony_ci FeedbackSlot real_element_slot = element_slot.Get(); 34781cb0ef41Sopenharmony_ci BuildFillArrayWithIterator(iterator, array, index, value, 34791cb0ef41Sopenharmony_ci next_value_load_slot, next_done_load_slot, 34801cb0ef41Sopenharmony_ci real_index_slot, real_element_slot); 34811cb0ef41Sopenharmony_ci } else if (!subexpr->IsTheHoleLiteral()) { 34821cb0ef41Sopenharmony_ci // literal[index++] = subexpr 34831cb0ef41Sopenharmony_ci VisitForAccumulatorValue(subexpr); 34841cb0ef41Sopenharmony_ci builder() 34851cb0ef41Sopenharmony_ci ->StoreInArrayLiteral(array, index, 34861cb0ef41Sopenharmony_ci feedback_index(element_slot.Get())) 34871cb0ef41Sopenharmony_ci .LoadAccumulatorWithRegister(index); 34881cb0ef41Sopenharmony_ci // Only increase the index if we are not the last element. 34891cb0ef41Sopenharmony_ci if (current + 1 != end) { 34901cb0ef41Sopenharmony_ci builder() 34911cb0ef41Sopenharmony_ci ->UnaryOperation(Token::INC, feedback_index(index_slot.Get())) 34921cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(index); 34931cb0ef41Sopenharmony_ci } 34941cb0ef41Sopenharmony_ci } else { 34951cb0ef41Sopenharmony_ci // literal.length = ++index 34961cb0ef41Sopenharmony_ci // length_slot is only used when there are holes. 34971cb0ef41Sopenharmony_ci auto length = ast_string_constants()->length_string(); 34981cb0ef41Sopenharmony_ci builder() 34991cb0ef41Sopenharmony_ci ->LoadAccumulatorWithRegister(index) 35001cb0ef41Sopenharmony_ci .UnaryOperation(Token::INC, feedback_index(index_slot.Get())) 35011cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(index) 35021cb0ef41Sopenharmony_ci .SetNamedProperty(array, length, feedback_index(length_slot.Get()), 35031cb0ef41Sopenharmony_ci LanguageMode::kStrict); 35041cb0ef41Sopenharmony_ci } 35051cb0ef41Sopenharmony_ci } 35061cb0ef41Sopenharmony_ci 35071cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(array); 35081cb0ef41Sopenharmony_ci} 35091cb0ef41Sopenharmony_ci 35101cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 35111cb0ef41Sopenharmony_ci expr->builder()->InitDepthAndFlags(); 35121cb0ef41Sopenharmony_ci BuildCreateArrayLiteral(expr->values(), expr); 35131cb0ef41Sopenharmony_ci} 35141cb0ef41Sopenharmony_ci 35151cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { 35161cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(proxy); 35171cb0ef41Sopenharmony_ci BuildVariableLoad(proxy->var(), proxy->hole_check_mode()); 35181cb0ef41Sopenharmony_ci} 35191cb0ef41Sopenharmony_ci 35201cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildVariableLoad(Variable* variable, 35211cb0ef41Sopenharmony_ci HoleCheckMode hole_check_mode, 35221cb0ef41Sopenharmony_ci TypeofMode typeof_mode) { 35231cb0ef41Sopenharmony_ci switch (variable->location()) { 35241cb0ef41Sopenharmony_ci case VariableLocation::LOCAL: { 35251cb0ef41Sopenharmony_ci Register source(builder()->Local(variable->index())); 35261cb0ef41Sopenharmony_ci // We need to load the variable into the accumulator, even when in a 35271cb0ef41Sopenharmony_ci // VisitForRegisterScope, in order to avoid register aliasing if 35281cb0ef41Sopenharmony_ci // subsequent expressions assign to the same variable. 35291cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(source); 35301cb0ef41Sopenharmony_ci if (hole_check_mode == HoleCheckMode::kRequired) { 35311cb0ef41Sopenharmony_ci BuildThrowIfHole(variable); 35321cb0ef41Sopenharmony_ci } 35331cb0ef41Sopenharmony_ci break; 35341cb0ef41Sopenharmony_ci } 35351cb0ef41Sopenharmony_ci case VariableLocation::PARAMETER: { 35361cb0ef41Sopenharmony_ci Register source; 35371cb0ef41Sopenharmony_ci if (variable->IsReceiver()) { 35381cb0ef41Sopenharmony_ci source = builder()->Receiver(); 35391cb0ef41Sopenharmony_ci } else { 35401cb0ef41Sopenharmony_ci source = builder()->Parameter(variable->index()); 35411cb0ef41Sopenharmony_ci } 35421cb0ef41Sopenharmony_ci // We need to load the variable into the accumulator, even when in a 35431cb0ef41Sopenharmony_ci // VisitForRegisterScope, in order to avoid register aliasing if 35441cb0ef41Sopenharmony_ci // subsequent expressions assign to the same variable. 35451cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(source); 35461cb0ef41Sopenharmony_ci if (hole_check_mode == HoleCheckMode::kRequired) { 35471cb0ef41Sopenharmony_ci BuildThrowIfHole(variable); 35481cb0ef41Sopenharmony_ci } 35491cb0ef41Sopenharmony_ci break; 35501cb0ef41Sopenharmony_ci } 35511cb0ef41Sopenharmony_ci case VariableLocation::UNALLOCATED: { 35521cb0ef41Sopenharmony_ci // The global identifier "undefined" is immutable. Everything 35531cb0ef41Sopenharmony_ci // else could be reassigned. For performance, we do a pointer comparison 35541cb0ef41Sopenharmony_ci // rather than checking if the raw_name is really "undefined". 35551cb0ef41Sopenharmony_ci if (variable->raw_name() == ast_string_constants()->undefined_string()) { 35561cb0ef41Sopenharmony_ci builder()->LoadUndefined(); 35571cb0ef41Sopenharmony_ci } else { 35581cb0ef41Sopenharmony_ci FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable); 35591cb0ef41Sopenharmony_ci builder()->LoadGlobal(variable->raw_name(), feedback_index(slot), 35601cb0ef41Sopenharmony_ci typeof_mode); 35611cb0ef41Sopenharmony_ci } 35621cb0ef41Sopenharmony_ci break; 35631cb0ef41Sopenharmony_ci } 35641cb0ef41Sopenharmony_ci case VariableLocation::CONTEXT: { 35651cb0ef41Sopenharmony_ci int depth = execution_context()->ContextChainDepth(variable->scope()); 35661cb0ef41Sopenharmony_ci ContextScope* context = execution_context()->Previous(depth); 35671cb0ef41Sopenharmony_ci Register context_reg; 35681cb0ef41Sopenharmony_ci if (context) { 35691cb0ef41Sopenharmony_ci context_reg = context->reg(); 35701cb0ef41Sopenharmony_ci depth = 0; 35711cb0ef41Sopenharmony_ci } else { 35721cb0ef41Sopenharmony_ci context_reg = execution_context()->reg(); 35731cb0ef41Sopenharmony_ci } 35741cb0ef41Sopenharmony_ci 35751cb0ef41Sopenharmony_ci BytecodeArrayBuilder::ContextSlotMutability immutable = 35761cb0ef41Sopenharmony_ci (variable->maybe_assigned() == kNotAssigned) 35771cb0ef41Sopenharmony_ci ? BytecodeArrayBuilder::kImmutableSlot 35781cb0ef41Sopenharmony_ci : BytecodeArrayBuilder::kMutableSlot; 35791cb0ef41Sopenharmony_ci 35801cb0ef41Sopenharmony_ci builder()->LoadContextSlot(context_reg, variable->index(), depth, 35811cb0ef41Sopenharmony_ci immutable); 35821cb0ef41Sopenharmony_ci if (hole_check_mode == HoleCheckMode::kRequired) { 35831cb0ef41Sopenharmony_ci BuildThrowIfHole(variable); 35841cb0ef41Sopenharmony_ci } 35851cb0ef41Sopenharmony_ci break; 35861cb0ef41Sopenharmony_ci } 35871cb0ef41Sopenharmony_ci case VariableLocation::LOOKUP: { 35881cb0ef41Sopenharmony_ci switch (variable->mode()) { 35891cb0ef41Sopenharmony_ci case VariableMode::kDynamicLocal: { 35901cb0ef41Sopenharmony_ci Variable* local_variable = variable->local_if_not_shadowed(); 35911cb0ef41Sopenharmony_ci int depth = 35921cb0ef41Sopenharmony_ci execution_context()->ContextChainDepth(local_variable->scope()); 35931cb0ef41Sopenharmony_ci builder()->LoadLookupContextSlot(variable->raw_name(), typeof_mode, 35941cb0ef41Sopenharmony_ci local_variable->index(), depth); 35951cb0ef41Sopenharmony_ci if (hole_check_mode == HoleCheckMode::kRequired) { 35961cb0ef41Sopenharmony_ci BuildThrowIfHole(variable); 35971cb0ef41Sopenharmony_ci } 35981cb0ef41Sopenharmony_ci break; 35991cb0ef41Sopenharmony_ci } 36001cb0ef41Sopenharmony_ci case VariableMode::kDynamicGlobal: { 36011cb0ef41Sopenharmony_ci int depth = 36021cb0ef41Sopenharmony_ci current_scope()->ContextChainLengthUntilOutermostSloppyEval(); 36031cb0ef41Sopenharmony_ci // TODO(1008414): Add back caching here when bug is fixed properly. 36041cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddLoadGlobalICSlot(typeof_mode); 36051cb0ef41Sopenharmony_ci 36061cb0ef41Sopenharmony_ci builder()->LoadLookupGlobalSlot(variable->raw_name(), typeof_mode, 36071cb0ef41Sopenharmony_ci feedback_index(slot), depth); 36081cb0ef41Sopenharmony_ci break; 36091cb0ef41Sopenharmony_ci } 36101cb0ef41Sopenharmony_ci default: 36111cb0ef41Sopenharmony_ci builder()->LoadLookupSlot(variable->raw_name(), typeof_mode); 36121cb0ef41Sopenharmony_ci } 36131cb0ef41Sopenharmony_ci break; 36141cb0ef41Sopenharmony_ci } 36151cb0ef41Sopenharmony_ci case VariableLocation::MODULE: { 36161cb0ef41Sopenharmony_ci int depth = execution_context()->ContextChainDepth(variable->scope()); 36171cb0ef41Sopenharmony_ci builder()->LoadModuleVariable(variable->index(), depth); 36181cb0ef41Sopenharmony_ci if (hole_check_mode == HoleCheckMode::kRequired) { 36191cb0ef41Sopenharmony_ci BuildThrowIfHole(variable); 36201cb0ef41Sopenharmony_ci } 36211cb0ef41Sopenharmony_ci break; 36221cb0ef41Sopenharmony_ci } 36231cb0ef41Sopenharmony_ci case VariableLocation::REPL_GLOBAL: { 36241cb0ef41Sopenharmony_ci DCHECK(variable->IsReplGlobal()); 36251cb0ef41Sopenharmony_ci FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable); 36261cb0ef41Sopenharmony_ci builder()->LoadGlobal(variable->raw_name(), feedback_index(slot), 36271cb0ef41Sopenharmony_ci typeof_mode); 36281cb0ef41Sopenharmony_ci break; 36291cb0ef41Sopenharmony_ci } 36301cb0ef41Sopenharmony_ci } 36311cb0ef41Sopenharmony_ci} 36321cb0ef41Sopenharmony_ci 36331cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildVariableLoadForAccumulatorValue( 36341cb0ef41Sopenharmony_ci Variable* variable, HoleCheckMode hole_check_mode, TypeofMode typeof_mode) { 36351cb0ef41Sopenharmony_ci ValueResultScope accumulator_result(this); 36361cb0ef41Sopenharmony_ci BuildVariableLoad(variable, hole_check_mode, typeof_mode); 36371cb0ef41Sopenharmony_ci} 36381cb0ef41Sopenharmony_ci 36391cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildReturn(int source_position) { 36401cb0ef41Sopenharmony_ci if (FLAG_trace) { 36411cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 36421cb0ef41Sopenharmony_ci Register result = register_allocator()->NewRegister(); 36431cb0ef41Sopenharmony_ci // Runtime returns {result} value, preserving accumulator. 36441cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(result).CallRuntime( 36451cb0ef41Sopenharmony_ci Runtime::kTraceExit, result); 36461cb0ef41Sopenharmony_ci } 36471cb0ef41Sopenharmony_ci if (info()->flags().collect_type_profile()) { 36481cb0ef41Sopenharmony_ci builder()->CollectTypeProfile(info()->literal()->return_position()); 36491cb0ef41Sopenharmony_ci } 36501cb0ef41Sopenharmony_ci builder()->SetStatementPosition(source_position); 36511cb0ef41Sopenharmony_ci builder()->Return(); 36521cb0ef41Sopenharmony_ci} 36531cb0ef41Sopenharmony_ci 36541cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildAsyncReturn(int source_position) { 36551cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 36561cb0ef41Sopenharmony_ci 36571cb0ef41Sopenharmony_ci if (IsAsyncGeneratorFunction(info()->literal()->kind())) { 36581cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(3); 36591cb0ef41Sopenharmony_ci builder() 36601cb0ef41Sopenharmony_ci ->MoveRegister(generator_object(), args[0]) // generator 36611cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) // value 36621cb0ef41Sopenharmony_ci .LoadTrue() 36631cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[2]) // done 36641cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kInlineAsyncGeneratorResolve, args); 36651cb0ef41Sopenharmony_ci } else { 36661cb0ef41Sopenharmony_ci DCHECK(IsAsyncFunction(info()->literal()->kind()) || 36671cb0ef41Sopenharmony_ci IsAsyncModule(info()->literal()->kind())); 36681cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 36691cb0ef41Sopenharmony_ci builder() 36701cb0ef41Sopenharmony_ci ->MoveRegister(generator_object(), args[0]) // generator 36711cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) // value 36721cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kInlineAsyncFunctionResolve, args); 36731cb0ef41Sopenharmony_ci } 36741cb0ef41Sopenharmony_ci 36751cb0ef41Sopenharmony_ci BuildReturn(source_position); 36761cb0ef41Sopenharmony_ci} 36771cb0ef41Sopenharmony_ci 36781cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); } 36791cb0ef41Sopenharmony_ci 36801cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildThrowIfHole(Variable* variable) { 36811cb0ef41Sopenharmony_ci if (variable->is_this()) { 36821cb0ef41Sopenharmony_ci DCHECK(variable->mode() == VariableMode::kConst); 36831cb0ef41Sopenharmony_ci builder()->ThrowSuperNotCalledIfHole(); 36841cb0ef41Sopenharmony_ci } else { 36851cb0ef41Sopenharmony_ci builder()->ThrowReferenceErrorIfHole(variable->raw_name()); 36861cb0ef41Sopenharmony_ci } 36871cb0ef41Sopenharmony_ci} 36881cb0ef41Sopenharmony_ci 36891cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable, 36901cb0ef41Sopenharmony_ci Token::Value op) { 36911cb0ef41Sopenharmony_ci DCHECK(!IsPrivateMethodOrAccessorVariableMode(variable->mode())); 36921cb0ef41Sopenharmony_ci if (variable->is_this() && variable->mode() == VariableMode::kConst && 36931cb0ef41Sopenharmony_ci op == Token::INIT) { 36941cb0ef41Sopenharmony_ci // Perform an initialization check for 'this'. 'this' variable is the 36951cb0ef41Sopenharmony_ci // only variable able to trigger bind operations outside the TDZ 36961cb0ef41Sopenharmony_ci // via 'super' calls. 36971cb0ef41Sopenharmony_ci builder()->ThrowSuperAlreadyCalledIfNotHole(); 36981cb0ef41Sopenharmony_ci } else { 36991cb0ef41Sopenharmony_ci // Perform an initialization check for let/const declared variables. 37001cb0ef41Sopenharmony_ci // E.g. let x = (x = 20); is not allowed. 37011cb0ef41Sopenharmony_ci DCHECK(IsLexicalVariableMode(variable->mode())); 37021cb0ef41Sopenharmony_ci BuildThrowIfHole(variable); 37031cb0ef41Sopenharmony_ci } 37041cb0ef41Sopenharmony_ci} 37051cb0ef41Sopenharmony_ci 37061cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildVariableAssignment( 37071cb0ef41Sopenharmony_ci Variable* variable, Token::Value op, HoleCheckMode hole_check_mode, 37081cb0ef41Sopenharmony_ci LookupHoistingMode lookup_hoisting_mode) { 37091cb0ef41Sopenharmony_ci VariableMode mode = variable->mode(); 37101cb0ef41Sopenharmony_ci RegisterAllocationScope assignment_register_scope(this); 37111cb0ef41Sopenharmony_ci BytecodeLabel end_label; 37121cb0ef41Sopenharmony_ci switch (variable->location()) { 37131cb0ef41Sopenharmony_ci case VariableLocation::PARAMETER: 37141cb0ef41Sopenharmony_ci case VariableLocation::LOCAL: { 37151cb0ef41Sopenharmony_ci Register destination; 37161cb0ef41Sopenharmony_ci if (VariableLocation::PARAMETER == variable->location()) { 37171cb0ef41Sopenharmony_ci if (variable->IsReceiver()) { 37181cb0ef41Sopenharmony_ci destination = builder()->Receiver(); 37191cb0ef41Sopenharmony_ci } else { 37201cb0ef41Sopenharmony_ci destination = builder()->Parameter(variable->index()); 37211cb0ef41Sopenharmony_ci } 37221cb0ef41Sopenharmony_ci } else { 37231cb0ef41Sopenharmony_ci destination = builder()->Local(variable->index()); 37241cb0ef41Sopenharmony_ci } 37251cb0ef41Sopenharmony_ci 37261cb0ef41Sopenharmony_ci if (hole_check_mode == HoleCheckMode::kRequired) { 37271cb0ef41Sopenharmony_ci // Load destination to check for hole. 37281cb0ef41Sopenharmony_ci Register value_temp = register_allocator()->NewRegister(); 37291cb0ef41Sopenharmony_ci builder() 37301cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(value_temp) 37311cb0ef41Sopenharmony_ci .LoadAccumulatorWithRegister(destination); 37321cb0ef41Sopenharmony_ci 37331cb0ef41Sopenharmony_ci BuildHoleCheckForVariableAssignment(variable, op); 37341cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value_temp); 37351cb0ef41Sopenharmony_ci } 37361cb0ef41Sopenharmony_ci 37371cb0ef41Sopenharmony_ci if (mode != VariableMode::kConst || op == Token::INIT) { 37381cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(destination); 37391cb0ef41Sopenharmony_ci } else if (variable->throw_on_const_assignment(language_mode())) { 37401cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kThrowConstAssignError); 37411cb0ef41Sopenharmony_ci } 37421cb0ef41Sopenharmony_ci break; 37431cb0ef41Sopenharmony_ci } 37441cb0ef41Sopenharmony_ci case VariableLocation::UNALLOCATED: { 37451cb0ef41Sopenharmony_ci BuildStoreGlobal(variable); 37461cb0ef41Sopenharmony_ci break; 37471cb0ef41Sopenharmony_ci } 37481cb0ef41Sopenharmony_ci case VariableLocation::CONTEXT: { 37491cb0ef41Sopenharmony_ci int depth = execution_context()->ContextChainDepth(variable->scope()); 37501cb0ef41Sopenharmony_ci ContextScope* context = execution_context()->Previous(depth); 37511cb0ef41Sopenharmony_ci Register context_reg; 37521cb0ef41Sopenharmony_ci 37531cb0ef41Sopenharmony_ci if (context) { 37541cb0ef41Sopenharmony_ci context_reg = context->reg(); 37551cb0ef41Sopenharmony_ci depth = 0; 37561cb0ef41Sopenharmony_ci } else { 37571cb0ef41Sopenharmony_ci context_reg = execution_context()->reg(); 37581cb0ef41Sopenharmony_ci } 37591cb0ef41Sopenharmony_ci 37601cb0ef41Sopenharmony_ci if (hole_check_mode == HoleCheckMode::kRequired) { 37611cb0ef41Sopenharmony_ci // Load destination to check for hole. 37621cb0ef41Sopenharmony_ci Register value_temp = register_allocator()->NewRegister(); 37631cb0ef41Sopenharmony_ci builder() 37641cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(value_temp) 37651cb0ef41Sopenharmony_ci .LoadContextSlot(context_reg, variable->index(), depth, 37661cb0ef41Sopenharmony_ci BytecodeArrayBuilder::kMutableSlot); 37671cb0ef41Sopenharmony_ci 37681cb0ef41Sopenharmony_ci BuildHoleCheckForVariableAssignment(variable, op); 37691cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value_temp); 37701cb0ef41Sopenharmony_ci } 37711cb0ef41Sopenharmony_ci 37721cb0ef41Sopenharmony_ci if (mode != VariableMode::kConst || op == Token::INIT) { 37731cb0ef41Sopenharmony_ci builder()->StoreContextSlot(context_reg, variable->index(), depth); 37741cb0ef41Sopenharmony_ci } else if (variable->throw_on_const_assignment(language_mode())) { 37751cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kThrowConstAssignError); 37761cb0ef41Sopenharmony_ci } 37771cb0ef41Sopenharmony_ci break; 37781cb0ef41Sopenharmony_ci } 37791cb0ef41Sopenharmony_ci case VariableLocation::LOOKUP: { 37801cb0ef41Sopenharmony_ci builder()->StoreLookupSlot(variable->raw_name(), language_mode(), 37811cb0ef41Sopenharmony_ci lookup_hoisting_mode); 37821cb0ef41Sopenharmony_ci break; 37831cb0ef41Sopenharmony_ci } 37841cb0ef41Sopenharmony_ci case VariableLocation::MODULE: { 37851cb0ef41Sopenharmony_ci DCHECK(IsDeclaredVariableMode(mode)); 37861cb0ef41Sopenharmony_ci 37871cb0ef41Sopenharmony_ci if (mode == VariableMode::kConst && op != Token::INIT) { 37881cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kThrowConstAssignError); 37891cb0ef41Sopenharmony_ci break; 37901cb0ef41Sopenharmony_ci } 37911cb0ef41Sopenharmony_ci 37921cb0ef41Sopenharmony_ci // If we don't throw above, we know that we're dealing with an 37931cb0ef41Sopenharmony_ci // export because imports are const and we do not generate initializing 37941cb0ef41Sopenharmony_ci // assignments for them. 37951cb0ef41Sopenharmony_ci DCHECK(variable->IsExport()); 37961cb0ef41Sopenharmony_ci 37971cb0ef41Sopenharmony_ci int depth = execution_context()->ContextChainDepth(variable->scope()); 37981cb0ef41Sopenharmony_ci if (hole_check_mode == HoleCheckMode::kRequired) { 37991cb0ef41Sopenharmony_ci Register value_temp = register_allocator()->NewRegister(); 38001cb0ef41Sopenharmony_ci builder() 38011cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(value_temp) 38021cb0ef41Sopenharmony_ci .LoadModuleVariable(variable->index(), depth); 38031cb0ef41Sopenharmony_ci BuildHoleCheckForVariableAssignment(variable, op); 38041cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value_temp); 38051cb0ef41Sopenharmony_ci } 38061cb0ef41Sopenharmony_ci builder()->StoreModuleVariable(variable->index(), depth); 38071cb0ef41Sopenharmony_ci break; 38081cb0ef41Sopenharmony_ci } 38091cb0ef41Sopenharmony_ci case VariableLocation::REPL_GLOBAL: { 38101cb0ef41Sopenharmony_ci // A let or const declaration like 'let x = 7' is effectively translated 38111cb0ef41Sopenharmony_ci // to: 38121cb0ef41Sopenharmony_ci // <top of the script>: 38131cb0ef41Sopenharmony_ci // ScriptContext.x = TheHole; 38141cb0ef41Sopenharmony_ci // ... 38151cb0ef41Sopenharmony_ci // <where the actual 'let' is>: 38161cb0ef41Sopenharmony_ci // ScriptContextTable.x = 7; // no hole check 38171cb0ef41Sopenharmony_ci // 38181cb0ef41Sopenharmony_ci // The ScriptContext slot for 'x' that we store to here is not 38191cb0ef41Sopenharmony_ci // necessarily the ScriptContext of this script, but rather the 38201cb0ef41Sopenharmony_ci // first ScriptContext that has a slot for name 'x'. 38211cb0ef41Sopenharmony_ci DCHECK(variable->IsReplGlobal()); 38221cb0ef41Sopenharmony_ci if (op == Token::INIT) { 38231cb0ef41Sopenharmony_ci RegisterList store_args = register_allocator()->NewRegisterList(2); 38241cb0ef41Sopenharmony_ci builder() 38251cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(store_args[1]) 38261cb0ef41Sopenharmony_ci .LoadLiteral(variable->raw_name()) 38271cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(store_args[0]); 38281cb0ef41Sopenharmony_ci builder()->CallRuntime( 38291cb0ef41Sopenharmony_ci Runtime::kStoreGlobalNoHoleCheckForReplLetOrConst, store_args); 38301cb0ef41Sopenharmony_ci } else { 38311cb0ef41Sopenharmony_ci if (mode == VariableMode::kConst) { 38321cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kThrowConstAssignError); 38331cb0ef41Sopenharmony_ci } else { 38341cb0ef41Sopenharmony_ci BuildStoreGlobal(variable); 38351cb0ef41Sopenharmony_ci } 38361cb0ef41Sopenharmony_ci } 38371cb0ef41Sopenharmony_ci break; 38381cb0ef41Sopenharmony_ci } 38391cb0ef41Sopenharmony_ci } 38401cb0ef41Sopenharmony_ci} 38411cb0ef41Sopenharmony_ci 38421cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildLoadNamedProperty(const Expression* object_expr, 38431cb0ef41Sopenharmony_ci Register object, 38441cb0ef41Sopenharmony_ci const AstRawString* name) { 38451cb0ef41Sopenharmony_ci FeedbackSlot slot = GetCachedLoadICSlot(object_expr, name); 38461cb0ef41Sopenharmony_ci builder()->LoadNamedProperty(object, name, feedback_index(slot)); 38471cb0ef41Sopenharmony_ci} 38481cb0ef41Sopenharmony_ci 38491cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildSetNamedProperty(const Expression* object_expr, 38501cb0ef41Sopenharmony_ci Register object, 38511cb0ef41Sopenharmony_ci const AstRawString* name) { 38521cb0ef41Sopenharmony_ci Register value; 38531cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 38541cb0ef41Sopenharmony_ci value = register_allocator()->NewRegister(); 38551cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(value); 38561cb0ef41Sopenharmony_ci } 38571cb0ef41Sopenharmony_ci 38581cb0ef41Sopenharmony_ci FeedbackSlot slot = GetCachedStoreICSlot(object_expr, name); 38591cb0ef41Sopenharmony_ci builder()->SetNamedProperty(object, name, feedback_index(slot), 38601cb0ef41Sopenharmony_ci language_mode()); 38611cb0ef41Sopenharmony_ci 38621cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 38631cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value); 38641cb0ef41Sopenharmony_ci } 38651cb0ef41Sopenharmony_ci} 38661cb0ef41Sopenharmony_ci 38671cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildStoreGlobal(Variable* variable) { 38681cb0ef41Sopenharmony_ci Register value; 38691cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 38701cb0ef41Sopenharmony_ci value = register_allocator()->NewRegister(); 38711cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(value); 38721cb0ef41Sopenharmony_ci } 38731cb0ef41Sopenharmony_ci 38741cb0ef41Sopenharmony_ci FeedbackSlot slot = GetCachedStoreGlobalICSlot(language_mode(), variable); 38751cb0ef41Sopenharmony_ci builder()->StoreGlobal(variable->raw_name(), feedback_index(slot)); 38761cb0ef41Sopenharmony_ci 38771cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 38781cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value); 38791cb0ef41Sopenharmony_ci } 38801cb0ef41Sopenharmony_ci} 38811cb0ef41Sopenharmony_ci 38821cb0ef41Sopenharmony_ci// static 38831cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData 38841cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData::NonProperty(Expression* expr) { 38851cb0ef41Sopenharmony_ci return AssignmentLhsData(NON_PROPERTY, expr, RegisterList(), Register(), 38861cb0ef41Sopenharmony_ci Register(), nullptr, nullptr); 38871cb0ef41Sopenharmony_ci} 38881cb0ef41Sopenharmony_ci// static 38891cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData 38901cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData::NamedProperty(Expression* object_expr, 38911cb0ef41Sopenharmony_ci Register object, 38921cb0ef41Sopenharmony_ci const AstRawString* name) { 38931cb0ef41Sopenharmony_ci return AssignmentLhsData(NAMED_PROPERTY, nullptr, RegisterList(), object, 38941cb0ef41Sopenharmony_ci Register(), object_expr, name); 38951cb0ef41Sopenharmony_ci} 38961cb0ef41Sopenharmony_ci// static 38971cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData 38981cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData::KeyedProperty(Register object, 38991cb0ef41Sopenharmony_ci Register key) { 39001cb0ef41Sopenharmony_ci return AssignmentLhsData(KEYED_PROPERTY, nullptr, RegisterList(), object, key, 39011cb0ef41Sopenharmony_ci nullptr, nullptr); 39021cb0ef41Sopenharmony_ci} 39031cb0ef41Sopenharmony_ci// static 39041cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData 39051cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData::NamedSuperProperty( 39061cb0ef41Sopenharmony_ci RegisterList super_property_args) { 39071cb0ef41Sopenharmony_ci return AssignmentLhsData(NAMED_SUPER_PROPERTY, nullptr, super_property_args, 39081cb0ef41Sopenharmony_ci Register(), Register(), nullptr, nullptr); 39091cb0ef41Sopenharmony_ci} 39101cb0ef41Sopenharmony_ci// static 39111cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData 39121cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData::PrivateMethodOrAccessor( 39131cb0ef41Sopenharmony_ci AssignType type, Property* property, Register object, Register key) { 39141cb0ef41Sopenharmony_ci return AssignmentLhsData(type, property, RegisterList(), object, key, nullptr, 39151cb0ef41Sopenharmony_ci nullptr); 39161cb0ef41Sopenharmony_ci} 39171cb0ef41Sopenharmony_ci// static 39181cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData 39191cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData::KeyedSuperProperty( 39201cb0ef41Sopenharmony_ci RegisterList super_property_args) { 39211cb0ef41Sopenharmony_ci return AssignmentLhsData(KEYED_SUPER_PROPERTY, nullptr, super_property_args, 39221cb0ef41Sopenharmony_ci Register(), Register(), nullptr, nullptr); 39231cb0ef41Sopenharmony_ci} 39241cb0ef41Sopenharmony_ci 39251cb0ef41Sopenharmony_ciBytecodeGenerator::AssignmentLhsData BytecodeGenerator::PrepareAssignmentLhs( 39261cb0ef41Sopenharmony_ci Expression* lhs, AccumulatorPreservingMode accumulator_preserving_mode) { 39271cb0ef41Sopenharmony_ci // Left-hand side can only be a property, a global or a variable slot. 39281cb0ef41Sopenharmony_ci Property* property = lhs->AsProperty(); 39291cb0ef41Sopenharmony_ci AssignType assign_type = Property::GetAssignType(property); 39301cb0ef41Sopenharmony_ci 39311cb0ef41Sopenharmony_ci // Evaluate LHS expression. 39321cb0ef41Sopenharmony_ci switch (assign_type) { 39331cb0ef41Sopenharmony_ci case NON_PROPERTY: 39341cb0ef41Sopenharmony_ci return AssignmentLhsData::NonProperty(lhs); 39351cb0ef41Sopenharmony_ci case NAMED_PROPERTY: { 39361cb0ef41Sopenharmony_ci AccumulatorPreservingScope scope(this, accumulator_preserving_mode); 39371cb0ef41Sopenharmony_ci Register object = VisitForRegisterValue(property->obj()); 39381cb0ef41Sopenharmony_ci const AstRawString* name = 39391cb0ef41Sopenharmony_ci property->key()->AsLiteral()->AsRawPropertyName(); 39401cb0ef41Sopenharmony_ci return AssignmentLhsData::NamedProperty(property->obj(), object, name); 39411cb0ef41Sopenharmony_ci } 39421cb0ef41Sopenharmony_ci case KEYED_PROPERTY: { 39431cb0ef41Sopenharmony_ci AccumulatorPreservingScope scope(this, accumulator_preserving_mode); 39441cb0ef41Sopenharmony_ci Register object = VisitForRegisterValue(property->obj()); 39451cb0ef41Sopenharmony_ci Register key = VisitForRegisterValue(property->key()); 39461cb0ef41Sopenharmony_ci return AssignmentLhsData::KeyedProperty(object, key); 39471cb0ef41Sopenharmony_ci } 39481cb0ef41Sopenharmony_ci case PRIVATE_METHOD: 39491cb0ef41Sopenharmony_ci case PRIVATE_GETTER_ONLY: 39501cb0ef41Sopenharmony_ci case PRIVATE_SETTER_ONLY: 39511cb0ef41Sopenharmony_ci case PRIVATE_GETTER_AND_SETTER: { 39521cb0ef41Sopenharmony_ci DCHECK(!property->IsSuperAccess()); 39531cb0ef41Sopenharmony_ci AccumulatorPreservingScope scope(this, accumulator_preserving_mode); 39541cb0ef41Sopenharmony_ci Register object = VisitForRegisterValue(property->obj()); 39551cb0ef41Sopenharmony_ci Register key = VisitForRegisterValue(property->key()); 39561cb0ef41Sopenharmony_ci return AssignmentLhsData::PrivateMethodOrAccessor(assign_type, property, 39571cb0ef41Sopenharmony_ci object, key); 39581cb0ef41Sopenharmony_ci } 39591cb0ef41Sopenharmony_ci case NAMED_SUPER_PROPERTY: { 39601cb0ef41Sopenharmony_ci AccumulatorPreservingScope scope(this, accumulator_preserving_mode); 39611cb0ef41Sopenharmony_ci RegisterList super_property_args = 39621cb0ef41Sopenharmony_ci register_allocator()->NewRegisterList(4); 39631cb0ef41Sopenharmony_ci BuildThisVariableLoad(); 39641cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(super_property_args[0]); 39651cb0ef41Sopenharmony_ci BuildVariableLoad( 39661cb0ef41Sopenharmony_ci property->obj()->AsSuperPropertyReference()->home_object()->var(), 39671cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 39681cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(super_property_args[1]); 39691cb0ef41Sopenharmony_ci builder() 39701cb0ef41Sopenharmony_ci ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 39711cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(super_property_args[2]); 39721cb0ef41Sopenharmony_ci return AssignmentLhsData::NamedSuperProperty(super_property_args); 39731cb0ef41Sopenharmony_ci } 39741cb0ef41Sopenharmony_ci case KEYED_SUPER_PROPERTY: { 39751cb0ef41Sopenharmony_ci AccumulatorPreservingScope scope(this, accumulator_preserving_mode); 39761cb0ef41Sopenharmony_ci RegisterList super_property_args = 39771cb0ef41Sopenharmony_ci register_allocator()->NewRegisterList(4); 39781cb0ef41Sopenharmony_ci BuildThisVariableLoad(); 39791cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(super_property_args[0]); 39801cb0ef41Sopenharmony_ci BuildVariableLoad( 39811cb0ef41Sopenharmony_ci property->obj()->AsSuperPropertyReference()->home_object()->var(), 39821cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 39831cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(super_property_args[1]); 39841cb0ef41Sopenharmony_ci VisitForRegisterValue(property->key(), super_property_args[2]); 39851cb0ef41Sopenharmony_ci return AssignmentLhsData::KeyedSuperProperty(super_property_args); 39861cb0ef41Sopenharmony_ci } 39871cb0ef41Sopenharmony_ci } 39881cb0ef41Sopenharmony_ci UNREACHABLE(); 39891cb0ef41Sopenharmony_ci} 39901cb0ef41Sopenharmony_ci 39911cb0ef41Sopenharmony_ci// Build the iteration finalizer called in the finally block of an iteration 39921cb0ef41Sopenharmony_ci// protocol execution. This closes the iterator if needed, and suppresses any 39931cb0ef41Sopenharmony_ci// exception it throws if necessary, including the exception when the return 39941cb0ef41Sopenharmony_ci// method is not callable. 39951cb0ef41Sopenharmony_ci// 39961cb0ef41Sopenharmony_ci// In pseudo-code, this builds: 39971cb0ef41Sopenharmony_ci// 39981cb0ef41Sopenharmony_ci// if (!done) { 39991cb0ef41Sopenharmony_ci// try { 40001cb0ef41Sopenharmony_ci// let method = iterator.return 40011cb0ef41Sopenharmony_ci// if (method !== null && method !== undefined) { 40021cb0ef41Sopenharmony_ci// let return_val = method.call(iterator) 40031cb0ef41Sopenharmony_ci// if (!%IsObject(return_val)) throw TypeError 40041cb0ef41Sopenharmony_ci// } 40051cb0ef41Sopenharmony_ci// } catch (e) { 40061cb0ef41Sopenharmony_ci// if (iteration_continuation != RETHROW) 40071cb0ef41Sopenharmony_ci// rethrow e 40081cb0ef41Sopenharmony_ci// } 40091cb0ef41Sopenharmony_ci// } 40101cb0ef41Sopenharmony_ci// 40111cb0ef41Sopenharmony_ci// For async iterators, iterator.close() becomes await iterator.close(). 40121cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildFinalizeIteration( 40131cb0ef41Sopenharmony_ci IteratorRecord iterator, Register done, 40141cb0ef41Sopenharmony_ci Register iteration_continuation_token) { 40151cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 40161cb0ef41Sopenharmony_ci BytecodeLabels iterator_is_done(zone()); 40171cb0ef41Sopenharmony_ci 40181cb0ef41Sopenharmony_ci // if (!done) { 40191cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(done).JumpIfTrue( 40201cb0ef41Sopenharmony_ci ToBooleanMode::kConvertToBoolean, iterator_is_done.New()); 40211cb0ef41Sopenharmony_ci 40221cb0ef41Sopenharmony_ci { 40231cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 40241cb0ef41Sopenharmony_ci BuildTryCatch( 40251cb0ef41Sopenharmony_ci // try { 40261cb0ef41Sopenharmony_ci // let method = iterator.return 40271cb0ef41Sopenharmony_ci // if (method !== null && method !== undefined) { 40281cb0ef41Sopenharmony_ci // let return_val = method.call(iterator) 40291cb0ef41Sopenharmony_ci // if (!%IsObject(return_val)) throw TypeError 40301cb0ef41Sopenharmony_ci // } 40311cb0ef41Sopenharmony_ci // } 40321cb0ef41Sopenharmony_ci [&]() { 40331cb0ef41Sopenharmony_ci Register method = register_allocator()->NewRegister(); 40341cb0ef41Sopenharmony_ci builder() 40351cb0ef41Sopenharmony_ci ->LoadNamedProperty( 40361cb0ef41Sopenharmony_ci iterator.object(), ast_string_constants()->return_string(), 40371cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLoadICSlot())) 40381cb0ef41Sopenharmony_ci .JumpIfUndefinedOrNull(iterator_is_done.New()) 40391cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(method); 40401cb0ef41Sopenharmony_ci 40411cb0ef41Sopenharmony_ci RegisterList args(iterator.object()); 40421cb0ef41Sopenharmony_ci builder()->CallProperty( 40431cb0ef41Sopenharmony_ci method, args, feedback_index(feedback_spec()->AddCallICSlot())); 40441cb0ef41Sopenharmony_ci if (iterator.type() == IteratorType::kAsync) { 40451cb0ef41Sopenharmony_ci BuildAwait(); 40461cb0ef41Sopenharmony_ci } 40471cb0ef41Sopenharmony_ci builder()->JumpIfJSReceiver(iterator_is_done.New()); 40481cb0ef41Sopenharmony_ci { 40491cb0ef41Sopenharmony_ci // Throw this exception inside the try block so that it is 40501cb0ef41Sopenharmony_ci // suppressed by the iteration continuation if necessary. 40511cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 40521cb0ef41Sopenharmony_ci Register return_result = register_allocator()->NewRegister(); 40531cb0ef41Sopenharmony_ci builder() 40541cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(return_result) 40551cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, 40561cb0ef41Sopenharmony_ci return_result); 40571cb0ef41Sopenharmony_ci } 40581cb0ef41Sopenharmony_ci }, 40591cb0ef41Sopenharmony_ci 40601cb0ef41Sopenharmony_ci // catch (e) { 40611cb0ef41Sopenharmony_ci // if (iteration_continuation != RETHROW) 40621cb0ef41Sopenharmony_ci // rethrow e 40631cb0ef41Sopenharmony_ci // } 40641cb0ef41Sopenharmony_ci [&](Register context) { 40651cb0ef41Sopenharmony_ci // Reuse context register to store the exception. 40661cb0ef41Sopenharmony_ci Register close_exception = context; 40671cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(close_exception); 40681cb0ef41Sopenharmony_ci 40691cb0ef41Sopenharmony_ci BytecodeLabel suppress_close_exception; 40701cb0ef41Sopenharmony_ci builder() 40711cb0ef41Sopenharmony_ci ->LoadLiteral( 40721cb0ef41Sopenharmony_ci Smi::FromInt(ControlScope::DeferredCommands::kRethrowToken)) 40731cb0ef41Sopenharmony_ci .CompareReference(iteration_continuation_token) 40741cb0ef41Sopenharmony_ci .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, 40751cb0ef41Sopenharmony_ci &suppress_close_exception) 40761cb0ef41Sopenharmony_ci .LoadAccumulatorWithRegister(close_exception) 40771cb0ef41Sopenharmony_ci .ReThrow() 40781cb0ef41Sopenharmony_ci .Bind(&suppress_close_exception); 40791cb0ef41Sopenharmony_ci }, 40801cb0ef41Sopenharmony_ci HandlerTable::UNCAUGHT); 40811cb0ef41Sopenharmony_ci } 40821cb0ef41Sopenharmony_ci 40831cb0ef41Sopenharmony_ci iterator_is_done.Bind(builder()); 40841cb0ef41Sopenharmony_ci} 40851cb0ef41Sopenharmony_ci 40861cb0ef41Sopenharmony_ci// Get the default value of a destructuring target. Will mutate the 40871cb0ef41Sopenharmony_ci// destructuring target expression if there is a default value. 40881cb0ef41Sopenharmony_ci// 40891cb0ef41Sopenharmony_ci// For 40901cb0ef41Sopenharmony_ci// a = b 40911cb0ef41Sopenharmony_ci// in 40921cb0ef41Sopenharmony_ci// let {a = b} = c 40931cb0ef41Sopenharmony_ci// returns b and mutates the input into a. 40941cb0ef41Sopenharmony_ciExpression* BytecodeGenerator::GetDestructuringDefaultValue( 40951cb0ef41Sopenharmony_ci Expression** target) { 40961cb0ef41Sopenharmony_ci Expression* default_value = nullptr; 40971cb0ef41Sopenharmony_ci if ((*target)->IsAssignment()) { 40981cb0ef41Sopenharmony_ci Assignment* default_init = (*target)->AsAssignment(); 40991cb0ef41Sopenharmony_ci DCHECK_EQ(default_init->op(), Token::ASSIGN); 41001cb0ef41Sopenharmony_ci default_value = default_init->value(); 41011cb0ef41Sopenharmony_ci *target = default_init->target(); 41021cb0ef41Sopenharmony_ci DCHECK((*target)->IsValidReferenceExpression() || (*target)->IsPattern()); 41031cb0ef41Sopenharmony_ci } 41041cb0ef41Sopenharmony_ci return default_value; 41051cb0ef41Sopenharmony_ci} 41061cb0ef41Sopenharmony_ci 41071cb0ef41Sopenharmony_ci// Convert a destructuring assignment to an array literal into a sequence of 41081cb0ef41Sopenharmony_ci// iterator accesses into the value being assigned (in the accumulator). 41091cb0ef41Sopenharmony_ci// 41101cb0ef41Sopenharmony_ci// [a().x, ...b] = accumulator 41111cb0ef41Sopenharmony_ci// 41121cb0ef41Sopenharmony_ci// becomes 41131cb0ef41Sopenharmony_ci// 41141cb0ef41Sopenharmony_ci// iterator = %GetIterator(accumulator) 41151cb0ef41Sopenharmony_ci// try { 41161cb0ef41Sopenharmony_ci// 41171cb0ef41Sopenharmony_ci// // Individual assignments read off the value from iterator.next() This gets 41181cb0ef41Sopenharmony_ci// // repeated per destructuring element. 41191cb0ef41Sopenharmony_ci// if (!done) { 41201cb0ef41Sopenharmony_ci// // Make sure we are considered 'done' if .next(), .done or .value fail. 41211cb0ef41Sopenharmony_ci// done = true 41221cb0ef41Sopenharmony_ci// var next_result = iterator.next() 41231cb0ef41Sopenharmony_ci// var tmp_done = next_result.done 41241cb0ef41Sopenharmony_ci// if (!tmp_done) { 41251cb0ef41Sopenharmony_ci// value = next_result.value 41261cb0ef41Sopenharmony_ci// done = false 41271cb0ef41Sopenharmony_ci// } 41281cb0ef41Sopenharmony_ci// } 41291cb0ef41Sopenharmony_ci// if (done) 41301cb0ef41Sopenharmony_ci// value = undefined 41311cb0ef41Sopenharmony_ci// a().x = value 41321cb0ef41Sopenharmony_ci// 41331cb0ef41Sopenharmony_ci// // A spread receives the remaining items in the iterator. 41341cb0ef41Sopenharmony_ci// var array = [] 41351cb0ef41Sopenharmony_ci// var index = 0 41361cb0ef41Sopenharmony_ci// %FillArrayWithIterator(iterator, array, index, done) 41371cb0ef41Sopenharmony_ci// done = true 41381cb0ef41Sopenharmony_ci// b = array 41391cb0ef41Sopenharmony_ci// 41401cb0ef41Sopenharmony_ci// } catch(e) { 41411cb0ef41Sopenharmony_ci// iteration_continuation = RETHROW 41421cb0ef41Sopenharmony_ci// } finally { 41431cb0ef41Sopenharmony_ci// %FinalizeIteration(iterator, done, iteration_continuation) 41441cb0ef41Sopenharmony_ci// } 41451cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildDestructuringArrayAssignment( 41461cb0ef41Sopenharmony_ci ArrayLiteral* pattern, Token::Value op, 41471cb0ef41Sopenharmony_ci LookupHoistingMode lookup_hoisting_mode) { 41481cb0ef41Sopenharmony_ci RegisterAllocationScope scope(this); 41491cb0ef41Sopenharmony_ci 41501cb0ef41Sopenharmony_ci Register value = register_allocator()->NewRegister(); 41511cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(value); 41521cb0ef41Sopenharmony_ci 41531cb0ef41Sopenharmony_ci // Store the iterator in a dedicated register so that it can be closed on 41541cb0ef41Sopenharmony_ci // exit, and the 'done' value in a dedicated register so that it can be 41551cb0ef41Sopenharmony_ci // changed and accessed independently of the iteration result. 41561cb0ef41Sopenharmony_ci IteratorRecord iterator = BuildGetIteratorRecord(IteratorType::kNormal); 41571cb0ef41Sopenharmony_ci Register done = register_allocator()->NewRegister(); 41581cb0ef41Sopenharmony_ci builder()->LoadFalse(); 41591cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(done); 41601cb0ef41Sopenharmony_ci 41611cb0ef41Sopenharmony_ci BuildTryFinally( 41621cb0ef41Sopenharmony_ci // Try block. 41631cb0ef41Sopenharmony_ci [&]() { 41641cb0ef41Sopenharmony_ci Register next_result = register_allocator()->NewRegister(); 41651cb0ef41Sopenharmony_ci FeedbackSlot next_value_load_slot = feedback_spec()->AddLoadICSlot(); 41661cb0ef41Sopenharmony_ci FeedbackSlot next_done_load_slot = feedback_spec()->AddLoadICSlot(); 41671cb0ef41Sopenharmony_ci 41681cb0ef41Sopenharmony_ci Spread* spread = nullptr; 41691cb0ef41Sopenharmony_ci for (Expression* target : *pattern->values()) { 41701cb0ef41Sopenharmony_ci if (target->IsSpread()) { 41711cb0ef41Sopenharmony_ci spread = target->AsSpread(); 41721cb0ef41Sopenharmony_ci break; 41731cb0ef41Sopenharmony_ci } 41741cb0ef41Sopenharmony_ci 41751cb0ef41Sopenharmony_ci Expression* default_value = GetDestructuringDefaultValue(&target); 41761cb0ef41Sopenharmony_ci if (!target->IsPattern()) { 41771cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(target); 41781cb0ef41Sopenharmony_ci } 41791cb0ef41Sopenharmony_ci 41801cb0ef41Sopenharmony_ci AssignmentLhsData lhs_data = PrepareAssignmentLhs(target); 41811cb0ef41Sopenharmony_ci 41821cb0ef41Sopenharmony_ci // if (!done) { 41831cb0ef41Sopenharmony_ci // // Make sure we are considered done if .next(), .done or .value 41841cb0ef41Sopenharmony_ci // // fail. 41851cb0ef41Sopenharmony_ci // done = true 41861cb0ef41Sopenharmony_ci // var next_result = iterator.next() 41871cb0ef41Sopenharmony_ci // var tmp_done = next_result.done 41881cb0ef41Sopenharmony_ci // if (!tmp_done) { 41891cb0ef41Sopenharmony_ci // value = next_result.value 41901cb0ef41Sopenharmony_ci // done = false 41911cb0ef41Sopenharmony_ci // } 41921cb0ef41Sopenharmony_ci // } 41931cb0ef41Sopenharmony_ci // if (done) 41941cb0ef41Sopenharmony_ci // value = undefined 41951cb0ef41Sopenharmony_ci BytecodeLabels is_done(zone()); 41961cb0ef41Sopenharmony_ci 41971cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(done); 41981cb0ef41Sopenharmony_ci builder()->JumpIfTrue(ToBooleanMode::kConvertToBoolean, 41991cb0ef41Sopenharmony_ci is_done.New()); 42001cb0ef41Sopenharmony_ci 42011cb0ef41Sopenharmony_ci builder()->LoadTrue().StoreAccumulatorInRegister(done); 42021cb0ef41Sopenharmony_ci BuildIteratorNext(iterator, next_result); 42031cb0ef41Sopenharmony_ci builder() 42041cb0ef41Sopenharmony_ci ->LoadNamedProperty(next_result, 42051cb0ef41Sopenharmony_ci ast_string_constants()->done_string(), 42061cb0ef41Sopenharmony_ci feedback_index(next_done_load_slot)) 42071cb0ef41Sopenharmony_ci .JumpIfTrue(ToBooleanMode::kConvertToBoolean, is_done.New()); 42081cb0ef41Sopenharmony_ci 42091cb0ef41Sopenharmony_ci // Only do the assignment if this is not a hole (i.e. 'elided'). 42101cb0ef41Sopenharmony_ci if (!target->IsTheHoleLiteral()) { 42111cb0ef41Sopenharmony_ci builder() 42121cb0ef41Sopenharmony_ci ->LoadNamedProperty(next_result, 42131cb0ef41Sopenharmony_ci ast_string_constants()->value_string(), 42141cb0ef41Sopenharmony_ci feedback_index(next_value_load_slot)) 42151cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(next_result) 42161cb0ef41Sopenharmony_ci .LoadFalse() 42171cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(done) 42181cb0ef41Sopenharmony_ci .LoadAccumulatorWithRegister(next_result); 42191cb0ef41Sopenharmony_ci 42201cb0ef41Sopenharmony_ci // [<pattern> = <init>] = <value> 42211cb0ef41Sopenharmony_ci // becomes (roughly) 42221cb0ef41Sopenharmony_ci // temp = <value>.next(); 42231cb0ef41Sopenharmony_ci // <pattern> = temp === undefined ? <init> : temp; 42241cb0ef41Sopenharmony_ci BytecodeLabel do_assignment; 42251cb0ef41Sopenharmony_ci if (default_value) { 42261cb0ef41Sopenharmony_ci builder()->JumpIfNotUndefined(&do_assignment); 42271cb0ef41Sopenharmony_ci // Since done == true => temp == undefined, jump directly to using 42281cb0ef41Sopenharmony_ci // the default value for that case. 42291cb0ef41Sopenharmony_ci is_done.Bind(builder()); 42301cb0ef41Sopenharmony_ci VisitForAccumulatorValue(default_value); 42311cb0ef41Sopenharmony_ci } else { 42321cb0ef41Sopenharmony_ci builder()->Jump(&do_assignment); 42331cb0ef41Sopenharmony_ci is_done.Bind(builder()); 42341cb0ef41Sopenharmony_ci builder()->LoadUndefined(); 42351cb0ef41Sopenharmony_ci } 42361cb0ef41Sopenharmony_ci builder()->Bind(&do_assignment); 42371cb0ef41Sopenharmony_ci 42381cb0ef41Sopenharmony_ci BuildAssignment(lhs_data, op, lookup_hoisting_mode); 42391cb0ef41Sopenharmony_ci } else { 42401cb0ef41Sopenharmony_ci builder()->LoadFalse().StoreAccumulatorInRegister(done); 42411cb0ef41Sopenharmony_ci DCHECK_EQ(lhs_data.assign_type(), NON_PROPERTY); 42421cb0ef41Sopenharmony_ci is_done.Bind(builder()); 42431cb0ef41Sopenharmony_ci } 42441cb0ef41Sopenharmony_ci } 42451cb0ef41Sopenharmony_ci 42461cb0ef41Sopenharmony_ci if (spread) { 42471cb0ef41Sopenharmony_ci RegisterAllocationScope scope(this); 42481cb0ef41Sopenharmony_ci BytecodeLabel is_done; 42491cb0ef41Sopenharmony_ci 42501cb0ef41Sopenharmony_ci // A spread is turned into a loop over the remainer of the iterator. 42511cb0ef41Sopenharmony_ci Expression* target = spread->expression(); 42521cb0ef41Sopenharmony_ci 42531cb0ef41Sopenharmony_ci if (!target->IsPattern()) { 42541cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(spread); 42551cb0ef41Sopenharmony_ci } 42561cb0ef41Sopenharmony_ci 42571cb0ef41Sopenharmony_ci AssignmentLhsData lhs_data = PrepareAssignmentLhs(target); 42581cb0ef41Sopenharmony_ci 42591cb0ef41Sopenharmony_ci // var array = []; 42601cb0ef41Sopenharmony_ci Register array = register_allocator()->NewRegister(); 42611cb0ef41Sopenharmony_ci builder()->CreateEmptyArrayLiteral( 42621cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLiteralSlot())); 42631cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(array); 42641cb0ef41Sopenharmony_ci 42651cb0ef41Sopenharmony_ci // If done, jump to assigning empty array 42661cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(done); 42671cb0ef41Sopenharmony_ci builder()->JumpIfTrue(ToBooleanMode::kConvertToBoolean, &is_done); 42681cb0ef41Sopenharmony_ci 42691cb0ef41Sopenharmony_ci // var index = 0; 42701cb0ef41Sopenharmony_ci Register index = register_allocator()->NewRegister(); 42711cb0ef41Sopenharmony_ci builder()->LoadLiteral(Smi::zero()); 42721cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(index); 42731cb0ef41Sopenharmony_ci 42741cb0ef41Sopenharmony_ci // Set done to true, since it's guaranteed to be true by the time the 42751cb0ef41Sopenharmony_ci // array fill completes. 42761cb0ef41Sopenharmony_ci builder()->LoadTrue().StoreAccumulatorInRegister(done); 42771cb0ef41Sopenharmony_ci 42781cb0ef41Sopenharmony_ci // Fill the array with the iterator. 42791cb0ef41Sopenharmony_ci FeedbackSlot element_slot = 42801cb0ef41Sopenharmony_ci feedback_spec()->AddStoreInArrayLiteralICSlot(); 42811cb0ef41Sopenharmony_ci FeedbackSlot index_slot = feedback_spec()->AddBinaryOpICSlot(); 42821cb0ef41Sopenharmony_ci BuildFillArrayWithIterator(iterator, array, index, next_result, 42831cb0ef41Sopenharmony_ci next_value_load_slot, next_done_load_slot, 42841cb0ef41Sopenharmony_ci index_slot, element_slot); 42851cb0ef41Sopenharmony_ci 42861cb0ef41Sopenharmony_ci builder()->Bind(&is_done); 42871cb0ef41Sopenharmony_ci // Assign the array to the LHS. 42881cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(array); 42891cb0ef41Sopenharmony_ci BuildAssignment(lhs_data, op, lookup_hoisting_mode); 42901cb0ef41Sopenharmony_ci } 42911cb0ef41Sopenharmony_ci }, 42921cb0ef41Sopenharmony_ci // Finally block. 42931cb0ef41Sopenharmony_ci [&](Register iteration_continuation_token) { 42941cb0ef41Sopenharmony_ci // Finish the iteration in the finally block. 42951cb0ef41Sopenharmony_ci BuildFinalizeIteration(iterator, done, iteration_continuation_token); 42961cb0ef41Sopenharmony_ci }, 42971cb0ef41Sopenharmony_ci HandlerTable::UNCAUGHT); 42981cb0ef41Sopenharmony_ci 42991cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 43001cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value); 43011cb0ef41Sopenharmony_ci } 43021cb0ef41Sopenharmony_ci} 43031cb0ef41Sopenharmony_ci 43041cb0ef41Sopenharmony_ci// Convert a destructuring assignment to an object literal into a sequence of 43051cb0ef41Sopenharmony_ci// property accesses into the value being assigned (in the accumulator). 43061cb0ef41Sopenharmony_ci// 43071cb0ef41Sopenharmony_ci// { y, [x++]: a(), ...b.c } = value 43081cb0ef41Sopenharmony_ci// 43091cb0ef41Sopenharmony_ci// becomes 43101cb0ef41Sopenharmony_ci// 43111cb0ef41Sopenharmony_ci// var rest_runtime_callargs = new Array(3); 43121cb0ef41Sopenharmony_ci// rest_runtime_callargs[0] = value; 43131cb0ef41Sopenharmony_ci// 43141cb0ef41Sopenharmony_ci// rest_runtime_callargs[1] = "y"; 43151cb0ef41Sopenharmony_ci// y = value.y; 43161cb0ef41Sopenharmony_ci// 43171cb0ef41Sopenharmony_ci// var temp1 = %ToName(x++); 43181cb0ef41Sopenharmony_ci// rest_runtime_callargs[2] = temp1; 43191cb0ef41Sopenharmony_ci// a() = value[temp1]; 43201cb0ef41Sopenharmony_ci// 43211cb0ef41Sopenharmony_ci// b.c = 43221cb0ef41Sopenharmony_ci// %CopyDataPropertiesWithExcludedPropertiesOnStack.call(rest_runtime_callargs); 43231cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildDestructuringObjectAssignment( 43241cb0ef41Sopenharmony_ci ObjectLiteral* pattern, Token::Value op, 43251cb0ef41Sopenharmony_ci LookupHoistingMode lookup_hoisting_mode) { 43261cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 43271cb0ef41Sopenharmony_ci 43281cb0ef41Sopenharmony_ci // Store the assignment value in a register. 43291cb0ef41Sopenharmony_ci Register value; 43301cb0ef41Sopenharmony_ci RegisterList rest_runtime_callargs; 43311cb0ef41Sopenharmony_ci if (pattern->builder()->has_rest_property()) { 43321cb0ef41Sopenharmony_ci rest_runtime_callargs = 43331cb0ef41Sopenharmony_ci register_allocator()->NewRegisterList(pattern->properties()->length()); 43341cb0ef41Sopenharmony_ci value = rest_runtime_callargs[0]; 43351cb0ef41Sopenharmony_ci } else { 43361cb0ef41Sopenharmony_ci value = register_allocator()->NewRegister(); 43371cb0ef41Sopenharmony_ci } 43381cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(value); 43391cb0ef41Sopenharmony_ci 43401cb0ef41Sopenharmony_ci // if (value === null || value === undefined) 43411cb0ef41Sopenharmony_ci // throw new TypeError(kNonCoercible); 43421cb0ef41Sopenharmony_ci // 43431cb0ef41Sopenharmony_ci // Since the first property access on null/undefined will also trigger a 43441cb0ef41Sopenharmony_ci // TypeError, we can elide this check. The exception is when there are no 43451cb0ef41Sopenharmony_ci // properties and no rest property (this is an empty literal), or when the 43461cb0ef41Sopenharmony_ci // first property is a computed name and accessing it can have side effects. 43471cb0ef41Sopenharmony_ci // 43481cb0ef41Sopenharmony_ci // TODO(leszeks): Also eliminate this check if the value is known to be 43491cb0ef41Sopenharmony_ci // non-null (e.g. an object literal). 43501cb0ef41Sopenharmony_ci if (pattern->properties()->is_empty() || 43511cb0ef41Sopenharmony_ci (pattern->properties()->at(0)->is_computed_name() && 43521cb0ef41Sopenharmony_ci pattern->properties()->at(0)->kind() != ObjectLiteralProperty::SPREAD)) { 43531cb0ef41Sopenharmony_ci BytecodeLabel is_null_or_undefined, not_null_or_undefined; 43541cb0ef41Sopenharmony_ci builder() 43551cb0ef41Sopenharmony_ci ->JumpIfUndefinedOrNull(&is_null_or_undefined) 43561cb0ef41Sopenharmony_ci .Jump(¬_null_or_undefined); 43571cb0ef41Sopenharmony_ci 43581cb0ef41Sopenharmony_ci { 43591cb0ef41Sopenharmony_ci builder()->Bind(&is_null_or_undefined); 43601cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(pattern); 43611cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kThrowPatternAssignmentNonCoercible, 43621cb0ef41Sopenharmony_ci value); 43631cb0ef41Sopenharmony_ci } 43641cb0ef41Sopenharmony_ci builder()->Bind(¬_null_or_undefined); 43651cb0ef41Sopenharmony_ci } 43661cb0ef41Sopenharmony_ci 43671cb0ef41Sopenharmony_ci int i = 0; 43681cb0ef41Sopenharmony_ci for (ObjectLiteralProperty* pattern_property : *pattern->properties()) { 43691cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 43701cb0ef41Sopenharmony_ci 43711cb0ef41Sopenharmony_ci // The key of the pattern becomes the key into the RHS value, and the value 43721cb0ef41Sopenharmony_ci // of the pattern becomes the target of the assignment. 43731cb0ef41Sopenharmony_ci // 43741cb0ef41Sopenharmony_ci // e.g. { a: b } = o becomes b = o.a 43751cb0ef41Sopenharmony_ci Expression* pattern_key = pattern_property->key(); 43761cb0ef41Sopenharmony_ci Expression* target = pattern_property->value(); 43771cb0ef41Sopenharmony_ci Expression* default_value = GetDestructuringDefaultValue(&target); 43781cb0ef41Sopenharmony_ci 43791cb0ef41Sopenharmony_ci if (!target->IsPattern()) { 43801cb0ef41Sopenharmony_ci builder()->SetExpressionAsStatementPosition(target); 43811cb0ef41Sopenharmony_ci } 43821cb0ef41Sopenharmony_ci 43831cb0ef41Sopenharmony_ci // Calculate this property's key into the assignment RHS value, additionally 43841cb0ef41Sopenharmony_ci // storing the key for rest_runtime_callargs if needed. 43851cb0ef41Sopenharmony_ci // 43861cb0ef41Sopenharmony_ci // The RHS is accessed using the key either by LoadNamedProperty (if 43871cb0ef41Sopenharmony_ci // value_name is valid) or by LoadKeyedProperty (otherwise). 43881cb0ef41Sopenharmony_ci const AstRawString* value_name = nullptr; 43891cb0ef41Sopenharmony_ci Register value_key; 43901cb0ef41Sopenharmony_ci 43911cb0ef41Sopenharmony_ci if (pattern_property->kind() != ObjectLiteralProperty::Kind::SPREAD) { 43921cb0ef41Sopenharmony_ci if (pattern_key->IsPropertyName()) { 43931cb0ef41Sopenharmony_ci value_name = pattern_key->AsLiteral()->AsRawPropertyName(); 43941cb0ef41Sopenharmony_ci } 43951cb0ef41Sopenharmony_ci if (pattern->builder()->has_rest_property() || !value_name) { 43961cb0ef41Sopenharmony_ci if (pattern->builder()->has_rest_property()) { 43971cb0ef41Sopenharmony_ci value_key = rest_runtime_callargs[i + 1]; 43981cb0ef41Sopenharmony_ci } else { 43991cb0ef41Sopenharmony_ci value_key = register_allocator()->NewRegister(); 44001cb0ef41Sopenharmony_ci } 44011cb0ef41Sopenharmony_ci if (pattern_property->is_computed_name()) { 44021cb0ef41Sopenharmony_ci // { [a()]: b().x } = c 44031cb0ef41Sopenharmony_ci // becomes 44041cb0ef41Sopenharmony_ci // var tmp = a() 44051cb0ef41Sopenharmony_ci // b().x = c[tmp] 44061cb0ef41Sopenharmony_ci DCHECK(!pattern_key->IsPropertyName() || 44071cb0ef41Sopenharmony_ci !pattern_key->IsNumberLiteral()); 44081cb0ef41Sopenharmony_ci VisitForAccumulatorValue(pattern_key); 44091cb0ef41Sopenharmony_ci builder()->ToName(value_key); 44101cb0ef41Sopenharmony_ci } else { 44111cb0ef41Sopenharmony_ci // We only need the key for non-computed properties when it is numeric 44121cb0ef41Sopenharmony_ci // or is being saved for the rest_runtime_callargs. 44131cb0ef41Sopenharmony_ci DCHECK(pattern_key->IsNumberLiteral() || 44141cb0ef41Sopenharmony_ci (pattern->builder()->has_rest_property() && 44151cb0ef41Sopenharmony_ci pattern_key->IsPropertyName())); 44161cb0ef41Sopenharmony_ci VisitForRegisterValue(pattern_key, value_key); 44171cb0ef41Sopenharmony_ci } 44181cb0ef41Sopenharmony_ci } 44191cb0ef41Sopenharmony_ci } 44201cb0ef41Sopenharmony_ci 44211cb0ef41Sopenharmony_ci AssignmentLhsData lhs_data = PrepareAssignmentLhs(target); 44221cb0ef41Sopenharmony_ci 44231cb0ef41Sopenharmony_ci // Get the value from the RHS. 44241cb0ef41Sopenharmony_ci if (pattern_property->kind() == ObjectLiteralProperty::Kind::SPREAD) { 44251cb0ef41Sopenharmony_ci DCHECK_EQ(i, pattern->properties()->length() - 1); 44261cb0ef41Sopenharmony_ci DCHECK(!value_key.is_valid()); 44271cb0ef41Sopenharmony_ci DCHECK_NULL(value_name); 44281cb0ef41Sopenharmony_ci builder()->CallRuntime( 44291cb0ef41Sopenharmony_ci Runtime::kInlineCopyDataPropertiesWithExcludedPropertiesOnStack, 44301cb0ef41Sopenharmony_ci rest_runtime_callargs); 44311cb0ef41Sopenharmony_ci } else if (value_name) { 44321cb0ef41Sopenharmony_ci builder()->LoadNamedProperty( 44331cb0ef41Sopenharmony_ci value, value_name, feedback_index(feedback_spec()->AddLoadICSlot())); 44341cb0ef41Sopenharmony_ci } else { 44351cb0ef41Sopenharmony_ci DCHECK(value_key.is_valid()); 44361cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value_key).LoadKeyedProperty( 44371cb0ef41Sopenharmony_ci value, feedback_index(feedback_spec()->AddKeyedLoadICSlot())); 44381cb0ef41Sopenharmony_ci } 44391cb0ef41Sopenharmony_ci 44401cb0ef41Sopenharmony_ci // {<pattern> = <init>} = <value> 44411cb0ef41Sopenharmony_ci // becomes 44421cb0ef41Sopenharmony_ci // temp = <value>; 44431cb0ef41Sopenharmony_ci // <pattern> = temp === undefined ? <init> : temp; 44441cb0ef41Sopenharmony_ci if (default_value) { 44451cb0ef41Sopenharmony_ci BytecodeLabel value_not_undefined; 44461cb0ef41Sopenharmony_ci builder()->JumpIfNotUndefined(&value_not_undefined); 44471cb0ef41Sopenharmony_ci VisitForAccumulatorValue(default_value); 44481cb0ef41Sopenharmony_ci builder()->Bind(&value_not_undefined); 44491cb0ef41Sopenharmony_ci } 44501cb0ef41Sopenharmony_ci 44511cb0ef41Sopenharmony_ci BuildAssignment(lhs_data, op, lookup_hoisting_mode); 44521cb0ef41Sopenharmony_ci 44531cb0ef41Sopenharmony_ci i++; 44541cb0ef41Sopenharmony_ci } 44551cb0ef41Sopenharmony_ci 44561cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 44571cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value); 44581cb0ef41Sopenharmony_ci } 44591cb0ef41Sopenharmony_ci} 44601cb0ef41Sopenharmony_ci 44611cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildAssignment( 44621cb0ef41Sopenharmony_ci const AssignmentLhsData& lhs_data, Token::Value op, 44631cb0ef41Sopenharmony_ci LookupHoistingMode lookup_hoisting_mode) { 44641cb0ef41Sopenharmony_ci // Assign the value to the LHS. 44651cb0ef41Sopenharmony_ci switch (lhs_data.assign_type()) { 44661cb0ef41Sopenharmony_ci case NON_PROPERTY: { 44671cb0ef41Sopenharmony_ci if (ObjectLiteral* pattern_as_object = 44681cb0ef41Sopenharmony_ci lhs_data.expr()->AsObjectLiteral()) { 44691cb0ef41Sopenharmony_ci // Split object literals into destructuring. 44701cb0ef41Sopenharmony_ci BuildDestructuringObjectAssignment(pattern_as_object, op, 44711cb0ef41Sopenharmony_ci lookup_hoisting_mode); 44721cb0ef41Sopenharmony_ci } else if (ArrayLiteral* pattern_as_array = 44731cb0ef41Sopenharmony_ci lhs_data.expr()->AsArrayLiteral()) { 44741cb0ef41Sopenharmony_ci // Split object literals into destructuring. 44751cb0ef41Sopenharmony_ci BuildDestructuringArrayAssignment(pattern_as_array, op, 44761cb0ef41Sopenharmony_ci lookup_hoisting_mode); 44771cb0ef41Sopenharmony_ci } else { 44781cb0ef41Sopenharmony_ci DCHECK(lhs_data.expr()->IsVariableProxy()); 44791cb0ef41Sopenharmony_ci VariableProxy* proxy = lhs_data.expr()->AsVariableProxy(); 44801cb0ef41Sopenharmony_ci BuildVariableAssignment(proxy->var(), op, proxy->hole_check_mode(), 44811cb0ef41Sopenharmony_ci lookup_hoisting_mode); 44821cb0ef41Sopenharmony_ci } 44831cb0ef41Sopenharmony_ci break; 44841cb0ef41Sopenharmony_ci } 44851cb0ef41Sopenharmony_ci case NAMED_PROPERTY: { 44861cb0ef41Sopenharmony_ci BuildSetNamedProperty(lhs_data.object_expr(), lhs_data.object(), 44871cb0ef41Sopenharmony_ci lhs_data.name()); 44881cb0ef41Sopenharmony_ci break; 44891cb0ef41Sopenharmony_ci } 44901cb0ef41Sopenharmony_ci case KEYED_PROPERTY: { 44911cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode()); 44921cb0ef41Sopenharmony_ci Register value; 44931cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 44941cb0ef41Sopenharmony_ci value = register_allocator()->NewRegister(); 44951cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(value); 44961cb0ef41Sopenharmony_ci } 44971cb0ef41Sopenharmony_ci builder()->SetKeyedProperty(lhs_data.object(), lhs_data.key(), 44981cb0ef41Sopenharmony_ci feedback_index(slot), language_mode()); 44991cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 45001cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value); 45011cb0ef41Sopenharmony_ci } 45021cb0ef41Sopenharmony_ci break; 45031cb0ef41Sopenharmony_ci } 45041cb0ef41Sopenharmony_ci case NAMED_SUPER_PROPERTY: { 45051cb0ef41Sopenharmony_ci builder() 45061cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(lhs_data.super_property_args()[3]) 45071cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kStoreToSuper, lhs_data.super_property_args()); 45081cb0ef41Sopenharmony_ci break; 45091cb0ef41Sopenharmony_ci } 45101cb0ef41Sopenharmony_ci case KEYED_SUPER_PROPERTY: { 45111cb0ef41Sopenharmony_ci builder() 45121cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(lhs_data.super_property_args()[3]) 45131cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kStoreKeyedToSuper, 45141cb0ef41Sopenharmony_ci lhs_data.super_property_args()); 45151cb0ef41Sopenharmony_ci break; 45161cb0ef41Sopenharmony_ci } 45171cb0ef41Sopenharmony_ci case PRIVATE_METHOD: { 45181cb0ef41Sopenharmony_ci Property* property = lhs_data.expr()->AsProperty(); 45191cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, lhs_data.object()); 45201cb0ef41Sopenharmony_ci BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateMethodWrite, 45211cb0ef41Sopenharmony_ci lhs_data.expr()->AsProperty()); 45221cb0ef41Sopenharmony_ci break; 45231cb0ef41Sopenharmony_ci } 45241cb0ef41Sopenharmony_ci case PRIVATE_GETTER_ONLY: { 45251cb0ef41Sopenharmony_ci Property* property = lhs_data.expr()->AsProperty(); 45261cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, lhs_data.object()); 45271cb0ef41Sopenharmony_ci BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateSetterAccess, 45281cb0ef41Sopenharmony_ci lhs_data.expr()->AsProperty()); 45291cb0ef41Sopenharmony_ci break; 45301cb0ef41Sopenharmony_ci } 45311cb0ef41Sopenharmony_ci case PRIVATE_SETTER_ONLY: 45321cb0ef41Sopenharmony_ci case PRIVATE_GETTER_AND_SETTER: { 45331cb0ef41Sopenharmony_ci Register value = register_allocator()->NewRegister(); 45341cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(value); 45351cb0ef41Sopenharmony_ci Property* property = lhs_data.expr()->AsProperty(); 45361cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, lhs_data.object()); 45371cb0ef41Sopenharmony_ci BuildPrivateSetterAccess(lhs_data.object(), lhs_data.key(), value); 45381cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 45391cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value); 45401cb0ef41Sopenharmony_ci } 45411cb0ef41Sopenharmony_ci break; 45421cb0ef41Sopenharmony_ci } 45431cb0ef41Sopenharmony_ci } 45441cb0ef41Sopenharmony_ci} 45451cb0ef41Sopenharmony_ci 45461cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitAssignment(Assignment* expr) { 45471cb0ef41Sopenharmony_ci AssignmentLhsData lhs_data = PrepareAssignmentLhs(expr->target()); 45481cb0ef41Sopenharmony_ci 45491cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->value()); 45501cb0ef41Sopenharmony_ci 45511cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 45521cb0ef41Sopenharmony_ci BuildAssignment(lhs_data, expr->op(), expr->lookup_hoisting_mode()); 45531cb0ef41Sopenharmony_ci} 45541cb0ef41Sopenharmony_ci 45551cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) { 45561cb0ef41Sopenharmony_ci AssignmentLhsData lhs_data = PrepareAssignmentLhs(expr->target()); 45571cb0ef41Sopenharmony_ci 45581cb0ef41Sopenharmony_ci // Evaluate the value and potentially handle compound assignments by loading 45591cb0ef41Sopenharmony_ci // the left-hand side value and performing a binary operation. 45601cb0ef41Sopenharmony_ci switch (lhs_data.assign_type()) { 45611cb0ef41Sopenharmony_ci case NON_PROPERTY: { 45621cb0ef41Sopenharmony_ci VariableProxy* proxy = expr->target()->AsVariableProxy(); 45631cb0ef41Sopenharmony_ci BuildVariableLoad(proxy->var(), proxy->hole_check_mode()); 45641cb0ef41Sopenharmony_ci break; 45651cb0ef41Sopenharmony_ci } 45661cb0ef41Sopenharmony_ci case NAMED_PROPERTY: { 45671cb0ef41Sopenharmony_ci BuildLoadNamedProperty(lhs_data.object_expr(), lhs_data.object(), 45681cb0ef41Sopenharmony_ci lhs_data.name()); 45691cb0ef41Sopenharmony_ci break; 45701cb0ef41Sopenharmony_ci } 45711cb0ef41Sopenharmony_ci case KEYED_PROPERTY: { 45721cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddKeyedLoadICSlot(); 45731cb0ef41Sopenharmony_ci builder() 45741cb0ef41Sopenharmony_ci ->LoadAccumulatorWithRegister(lhs_data.key()) 45751cb0ef41Sopenharmony_ci .LoadKeyedProperty(lhs_data.object(), feedback_index(slot)); 45761cb0ef41Sopenharmony_ci break; 45771cb0ef41Sopenharmony_ci } 45781cb0ef41Sopenharmony_ci case NAMED_SUPER_PROPERTY: { 45791cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kLoadFromSuper, 45801cb0ef41Sopenharmony_ci lhs_data.super_property_args().Truncate(3)); 45811cb0ef41Sopenharmony_ci break; 45821cb0ef41Sopenharmony_ci } 45831cb0ef41Sopenharmony_ci case KEYED_SUPER_PROPERTY: { 45841cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, 45851cb0ef41Sopenharmony_ci lhs_data.super_property_args().Truncate(3)); 45861cb0ef41Sopenharmony_ci break; 45871cb0ef41Sopenharmony_ci } 45881cb0ef41Sopenharmony_ci // BuildAssignment() will throw an error about the private method being 45891cb0ef41Sopenharmony_ci // read-only. 45901cb0ef41Sopenharmony_ci case PRIVATE_METHOD: { 45911cb0ef41Sopenharmony_ci Property* property = lhs_data.expr()->AsProperty(); 45921cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, lhs_data.object()); 45931cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(lhs_data.key()); 45941cb0ef41Sopenharmony_ci break; 45951cb0ef41Sopenharmony_ci } 45961cb0ef41Sopenharmony_ci // For read-only properties, BuildAssignment() will throw an error about 45971cb0ef41Sopenharmony_ci // the missing setter. 45981cb0ef41Sopenharmony_ci case PRIVATE_GETTER_ONLY: 45991cb0ef41Sopenharmony_ci case PRIVATE_GETTER_AND_SETTER: { 46001cb0ef41Sopenharmony_ci Property* property = lhs_data.expr()->AsProperty(); 46011cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, lhs_data.object()); 46021cb0ef41Sopenharmony_ci BuildPrivateGetterAccess(lhs_data.object(), lhs_data.key()); 46031cb0ef41Sopenharmony_ci break; 46041cb0ef41Sopenharmony_ci } 46051cb0ef41Sopenharmony_ci case PRIVATE_SETTER_ONLY: { 46061cb0ef41Sopenharmony_ci // The property access is invalid, but if the brand check fails too, we 46071cb0ef41Sopenharmony_ci // need to return the error from the brand check. 46081cb0ef41Sopenharmony_ci Property* property = lhs_data.expr()->AsProperty(); 46091cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, lhs_data.object()); 46101cb0ef41Sopenharmony_ci BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateGetterAccess, 46111cb0ef41Sopenharmony_ci lhs_data.expr()->AsProperty()); 46121cb0ef41Sopenharmony_ci break; 46131cb0ef41Sopenharmony_ci } 46141cb0ef41Sopenharmony_ci } 46151cb0ef41Sopenharmony_ci 46161cb0ef41Sopenharmony_ci BinaryOperation* binop = expr->binary_operation(); 46171cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot(); 46181cb0ef41Sopenharmony_ci BytecodeLabel short_circuit; 46191cb0ef41Sopenharmony_ci if (binop->op() == Token::NULLISH) { 46201cb0ef41Sopenharmony_ci BytecodeLabel nullish; 46211cb0ef41Sopenharmony_ci builder() 46221cb0ef41Sopenharmony_ci ->JumpIfUndefinedOrNull(&nullish) 46231cb0ef41Sopenharmony_ci .Jump(&short_circuit) 46241cb0ef41Sopenharmony_ci .Bind(&nullish); 46251cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->value()); 46261cb0ef41Sopenharmony_ci } else if (binop->op() == Token::OR) { 46271cb0ef41Sopenharmony_ci builder()->JumpIfTrue(ToBooleanMode::kConvertToBoolean, &short_circuit); 46281cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->value()); 46291cb0ef41Sopenharmony_ci } else if (binop->op() == Token::AND) { 46301cb0ef41Sopenharmony_ci builder()->JumpIfFalse(ToBooleanMode::kConvertToBoolean, &short_circuit); 46311cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->value()); 46321cb0ef41Sopenharmony_ci } else if (expr->value()->IsSmiLiteral()) { 46331cb0ef41Sopenharmony_ci builder()->BinaryOperationSmiLiteral( 46341cb0ef41Sopenharmony_ci binop->op(), expr->value()->AsLiteral()->AsSmiLiteral(), 46351cb0ef41Sopenharmony_ci feedback_index(slot)); 46361cb0ef41Sopenharmony_ci } else { 46371cb0ef41Sopenharmony_ci Register old_value = register_allocator()->NewRegister(); 46381cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(old_value); 46391cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->value()); 46401cb0ef41Sopenharmony_ci builder()->BinaryOperation(binop->op(), old_value, feedback_index(slot)); 46411cb0ef41Sopenharmony_ci } 46421cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 46431cb0ef41Sopenharmony_ci 46441cb0ef41Sopenharmony_ci BuildAssignment(lhs_data, expr->op(), expr->lookup_hoisting_mode()); 46451cb0ef41Sopenharmony_ci builder()->Bind(&short_circuit); 46461cb0ef41Sopenharmony_ci} 46471cb0ef41Sopenharmony_ci 46481cb0ef41Sopenharmony_ci// Suspends the generator to resume at the next suspend_id, with output stored 46491cb0ef41Sopenharmony_ci// in the accumulator. When the generator is resumed, the sent value is loaded 46501cb0ef41Sopenharmony_ci// in the accumulator. 46511cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildSuspendPoint(int position) { 46521cb0ef41Sopenharmony_ci // Because we eliminate jump targets in dead code, we also eliminate resumes 46531cb0ef41Sopenharmony_ci // when the suspend is not emitted because otherwise the below call to Bind 46541cb0ef41Sopenharmony_ci // would start a new basic block and the code would be considered alive. 46551cb0ef41Sopenharmony_ci if (builder()->RemainderOfBlockIsDead()) { 46561cb0ef41Sopenharmony_ci return; 46571cb0ef41Sopenharmony_ci } 46581cb0ef41Sopenharmony_ci const int suspend_id = suspend_count_++; 46591cb0ef41Sopenharmony_ci 46601cb0ef41Sopenharmony_ci RegisterList registers = register_allocator()->AllLiveRegisters(); 46611cb0ef41Sopenharmony_ci 46621cb0ef41Sopenharmony_ci // Save context, registers, and state. This bytecode then returns the value 46631cb0ef41Sopenharmony_ci // in the accumulator. 46641cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(position); 46651cb0ef41Sopenharmony_ci builder()->SuspendGenerator(generator_object(), registers, suspend_id); 46661cb0ef41Sopenharmony_ci 46671cb0ef41Sopenharmony_ci // Upon resume, we continue here. 46681cb0ef41Sopenharmony_ci builder()->Bind(generator_jump_table_, suspend_id); 46691cb0ef41Sopenharmony_ci 46701cb0ef41Sopenharmony_ci // Clobbers all registers and sets the accumulator to the 46711cb0ef41Sopenharmony_ci // [[input_or_debug_pos]] slot of the generator object. 46721cb0ef41Sopenharmony_ci builder()->ResumeGenerator(generator_object(), registers); 46731cb0ef41Sopenharmony_ci} 46741cb0ef41Sopenharmony_ci 46751cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitYield(Yield* expr) { 46761cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 46771cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->expression()); 46781cb0ef41Sopenharmony_ci 46791cb0ef41Sopenharmony_ci // If this is not the first yield 46801cb0ef41Sopenharmony_ci if (suspend_count_ > 0) { 46811cb0ef41Sopenharmony_ci if (IsAsyncGeneratorFunction(function_kind())) { 46821cb0ef41Sopenharmony_ci // AsyncGenerator yields (with the exception of the initial yield) 46831cb0ef41Sopenharmony_ci // delegate work to the AsyncGeneratorYield stub, which Awaits the operand 46841cb0ef41Sopenharmony_ci // and on success, wraps the value in an IteratorResult. 46851cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 46861cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(3); 46871cb0ef41Sopenharmony_ci builder() 46881cb0ef41Sopenharmony_ci ->MoveRegister(generator_object(), args[0]) // generator 46891cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) // value 46901cb0ef41Sopenharmony_ci .LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT) 46911cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[2]) // is_caught 46921cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kInlineAsyncGeneratorYield, args); 46931cb0ef41Sopenharmony_ci } else { 46941cb0ef41Sopenharmony_ci // Generator yields (with the exception of the initial yield) wrap the 46951cb0ef41Sopenharmony_ci // value into IteratorResult. 46961cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 46971cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 46981cb0ef41Sopenharmony_ci builder() 46991cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(args[0]) // value 47001cb0ef41Sopenharmony_ci .LoadFalse() 47011cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) // done 47021cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kInlineCreateIterResultObject, args); 47031cb0ef41Sopenharmony_ci } 47041cb0ef41Sopenharmony_ci } 47051cb0ef41Sopenharmony_ci 47061cb0ef41Sopenharmony_ci BuildSuspendPoint(expr->position()); 47071cb0ef41Sopenharmony_ci // At this point, the generator has been resumed, with the received value in 47081cb0ef41Sopenharmony_ci // the accumulator. 47091cb0ef41Sopenharmony_ci 47101cb0ef41Sopenharmony_ci // TODO(caitp): remove once yield* desugaring for async generators is handled 47111cb0ef41Sopenharmony_ci // in BytecodeGenerator. 47121cb0ef41Sopenharmony_ci if (expr->on_abrupt_resume() == Yield::kNoControl) { 47131cb0ef41Sopenharmony_ci DCHECK(IsAsyncGeneratorFunction(function_kind())); 47141cb0ef41Sopenharmony_ci return; 47151cb0ef41Sopenharmony_ci } 47161cb0ef41Sopenharmony_ci 47171cb0ef41Sopenharmony_ci Register input = register_allocator()->NewRegister(); 47181cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(input).CallRuntime( 47191cb0ef41Sopenharmony_ci Runtime::kInlineGeneratorGetResumeMode, generator_object()); 47201cb0ef41Sopenharmony_ci 47211cb0ef41Sopenharmony_ci // Now dispatch on resume mode. 47221cb0ef41Sopenharmony_ci STATIC_ASSERT(JSGeneratorObject::kNext + 1 == JSGeneratorObject::kReturn); 47231cb0ef41Sopenharmony_ci BytecodeJumpTable* jump_table = 47241cb0ef41Sopenharmony_ci builder()->AllocateJumpTable(2, JSGeneratorObject::kNext); 47251cb0ef41Sopenharmony_ci 47261cb0ef41Sopenharmony_ci builder()->SwitchOnSmiNoFeedback(jump_table); 47271cb0ef41Sopenharmony_ci 47281cb0ef41Sopenharmony_ci { 47291cb0ef41Sopenharmony_ci // Resume with throw (switch fallthrough). 47301cb0ef41Sopenharmony_ci // TODO(leszeks): Add a debug-only check that the accumulator is 47311cb0ef41Sopenharmony_ci // JSGeneratorObject::kThrow. 47321cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 47331cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(input); 47341cb0ef41Sopenharmony_ci builder()->Throw(); 47351cb0ef41Sopenharmony_ci } 47361cb0ef41Sopenharmony_ci 47371cb0ef41Sopenharmony_ci { 47381cb0ef41Sopenharmony_ci // Resume with return. 47391cb0ef41Sopenharmony_ci builder()->Bind(jump_table, JSGeneratorObject::kReturn); 47401cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(input); 47411cb0ef41Sopenharmony_ci if (IsAsyncGeneratorFunction(function_kind())) { 47421cb0ef41Sopenharmony_ci execution_control()->AsyncReturnAccumulator(kNoSourcePosition); 47431cb0ef41Sopenharmony_ci } else { 47441cb0ef41Sopenharmony_ci execution_control()->ReturnAccumulator(kNoSourcePosition); 47451cb0ef41Sopenharmony_ci } 47461cb0ef41Sopenharmony_ci } 47471cb0ef41Sopenharmony_ci 47481cb0ef41Sopenharmony_ci { 47491cb0ef41Sopenharmony_ci // Resume with next. 47501cb0ef41Sopenharmony_ci builder()->Bind(jump_table, JSGeneratorObject::kNext); 47511cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(expr, 47521cb0ef41Sopenharmony_ci SourceRangeKind::kContinuation); 47531cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(input); 47541cb0ef41Sopenharmony_ci } 47551cb0ef41Sopenharmony_ci} 47561cb0ef41Sopenharmony_ci 47571cb0ef41Sopenharmony_ci// Desugaring of (yield* iterable) 47581cb0ef41Sopenharmony_ci// 47591cb0ef41Sopenharmony_ci// do { 47601cb0ef41Sopenharmony_ci// const kNext = 0; 47611cb0ef41Sopenharmony_ci// const kReturn = 1; 47621cb0ef41Sopenharmony_ci// const kThrow = 2; 47631cb0ef41Sopenharmony_ci// 47641cb0ef41Sopenharmony_ci// let output; // uninitialized 47651cb0ef41Sopenharmony_ci// 47661cb0ef41Sopenharmony_ci// let iteratorRecord = GetIterator(iterable); 47671cb0ef41Sopenharmony_ci// let iterator = iteratorRecord.[[Iterator]]; 47681cb0ef41Sopenharmony_ci// let next = iteratorRecord.[[NextMethod]]; 47691cb0ef41Sopenharmony_ci// let input = undefined; 47701cb0ef41Sopenharmony_ci// let resumeMode = kNext; 47711cb0ef41Sopenharmony_ci// 47721cb0ef41Sopenharmony_ci// while (true) { 47731cb0ef41Sopenharmony_ci// // From the generator to the iterator: 47741cb0ef41Sopenharmony_ci// // Forward input according to resumeMode and obtain output. 47751cb0ef41Sopenharmony_ci// switch (resumeMode) { 47761cb0ef41Sopenharmony_ci// case kNext: 47771cb0ef41Sopenharmony_ci// output = next.[[Call]](iterator, « »);; 47781cb0ef41Sopenharmony_ci// break; 47791cb0ef41Sopenharmony_ci// case kReturn: 47801cb0ef41Sopenharmony_ci// let iteratorReturn = iterator.return; 47811cb0ef41Sopenharmony_ci// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) { 47821cb0ef41Sopenharmony_ci// if (IS_ASYNC_GENERATOR) input = await input; 47831cb0ef41Sopenharmony_ci// return input; 47841cb0ef41Sopenharmony_ci// } 47851cb0ef41Sopenharmony_ci// output = iteratorReturn.[[Call]](iterator, «input»); 47861cb0ef41Sopenharmony_ci// break; 47871cb0ef41Sopenharmony_ci// case kThrow: 47881cb0ef41Sopenharmony_ci// let iteratorThrow = iterator.throw; 47891cb0ef41Sopenharmony_ci// if (IS_NULL_OR_UNDEFINED(iteratorThrow)) { 47901cb0ef41Sopenharmony_ci// let iteratorReturn = iterator.return; 47911cb0ef41Sopenharmony_ci// if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { 47921cb0ef41Sopenharmony_ci// output = iteratorReturn.[[Call]](iterator, « »); 47931cb0ef41Sopenharmony_ci// if (IS_ASYNC_GENERATOR) output = await output; 47941cb0ef41Sopenharmony_ci// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output); 47951cb0ef41Sopenharmony_ci// } 47961cb0ef41Sopenharmony_ci// throw MakeTypeError(kThrowMethodMissing); 47971cb0ef41Sopenharmony_ci// } 47981cb0ef41Sopenharmony_ci// output = iteratorThrow.[[Call]](iterator, «input»); 47991cb0ef41Sopenharmony_ci// break; 48001cb0ef41Sopenharmony_ci// } 48011cb0ef41Sopenharmony_ci// 48021cb0ef41Sopenharmony_ci// if (IS_ASYNC_GENERATOR) output = await output; 48031cb0ef41Sopenharmony_ci// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output); 48041cb0ef41Sopenharmony_ci// if (output.done) break; 48051cb0ef41Sopenharmony_ci// 48061cb0ef41Sopenharmony_ci// // From the generator to its user: 48071cb0ef41Sopenharmony_ci// // Forward output, receive new input, and determine resume mode. 48081cb0ef41Sopenharmony_ci// if (IS_ASYNC_GENERATOR) { 48091cb0ef41Sopenharmony_ci// // AsyncGeneratorYield abstract operation awaits the operand before 48101cb0ef41Sopenharmony_ci// // resolving the promise for the current AsyncGeneratorRequest. 48111cb0ef41Sopenharmony_ci// %_AsyncGeneratorYield(output.value) 48121cb0ef41Sopenharmony_ci// } 48131cb0ef41Sopenharmony_ci// input = Suspend(output); 48141cb0ef41Sopenharmony_ci// resumeMode = %GeneratorGetResumeMode(); 48151cb0ef41Sopenharmony_ci// } 48161cb0ef41Sopenharmony_ci// 48171cb0ef41Sopenharmony_ci// if (resumeMode === kReturn) { 48181cb0ef41Sopenharmony_ci// return output.value; 48191cb0ef41Sopenharmony_ci// } 48201cb0ef41Sopenharmony_ci// output.value 48211cb0ef41Sopenharmony_ci// } 48221cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitYieldStar(YieldStar* expr) { 48231cb0ef41Sopenharmony_ci Register output = register_allocator()->NewRegister(); 48241cb0ef41Sopenharmony_ci Register resume_mode = register_allocator()->NewRegister(); 48251cb0ef41Sopenharmony_ci IteratorType iterator_type = IsAsyncGeneratorFunction(function_kind()) 48261cb0ef41Sopenharmony_ci ? IteratorType::kAsync 48271cb0ef41Sopenharmony_ci : IteratorType::kNormal; 48281cb0ef41Sopenharmony_ci 48291cb0ef41Sopenharmony_ci { 48301cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 48311cb0ef41Sopenharmony_ci RegisterList iterator_and_input = register_allocator()->NewRegisterList(2); 48321cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->expression()); 48331cb0ef41Sopenharmony_ci IteratorRecord iterator = BuildGetIteratorRecord( 48341cb0ef41Sopenharmony_ci register_allocator()->NewRegister() /* next method */, 48351cb0ef41Sopenharmony_ci iterator_and_input[0], iterator_type); 48361cb0ef41Sopenharmony_ci 48371cb0ef41Sopenharmony_ci Register input = iterator_and_input[1]; 48381cb0ef41Sopenharmony_ci builder()->LoadUndefined().StoreAccumulatorInRegister(input); 48391cb0ef41Sopenharmony_ci builder() 48401cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) 48411cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(resume_mode); 48421cb0ef41Sopenharmony_ci 48431cb0ef41Sopenharmony_ci { 48441cb0ef41Sopenharmony_ci // This loop builder does not construct counters as the loop is not 48451cb0ef41Sopenharmony_ci // visible to the user, and we therefore neither pass the block coverage 48461cb0ef41Sopenharmony_ci // builder nor the expression. 48471cb0ef41Sopenharmony_ci // 48481cb0ef41Sopenharmony_ci // In addition to the normal suspend for yield*, a yield* in an async 48491cb0ef41Sopenharmony_ci // generator has 2 additional suspends: 48501cb0ef41Sopenharmony_ci // - One for awaiting the iterator result of closing the generator when 48511cb0ef41Sopenharmony_ci // resumed with a "throw" completion, and a throw method is not 48521cb0ef41Sopenharmony_ci // present on the delegated iterator 48531cb0ef41Sopenharmony_ci // - One for awaiting the iterator result yielded by the delegated 48541cb0ef41Sopenharmony_ci // iterator 48551cb0ef41Sopenharmony_ci 48561cb0ef41Sopenharmony_ci LoopBuilder loop_builder(builder(), nullptr, nullptr); 48571cb0ef41Sopenharmony_ci LoopScope loop_scope(this, &loop_builder); 48581cb0ef41Sopenharmony_ci 48591cb0ef41Sopenharmony_ci { 48601cb0ef41Sopenharmony_ci BytecodeLabels after_switch(zone()); 48611cb0ef41Sopenharmony_ci BytecodeJumpTable* switch_jump_table = 48621cb0ef41Sopenharmony_ci builder()->AllocateJumpTable(2, 1); 48631cb0ef41Sopenharmony_ci 48641cb0ef41Sopenharmony_ci builder() 48651cb0ef41Sopenharmony_ci ->LoadAccumulatorWithRegister(resume_mode) 48661cb0ef41Sopenharmony_ci .SwitchOnSmiNoFeedback(switch_jump_table); 48671cb0ef41Sopenharmony_ci 48681cb0ef41Sopenharmony_ci // Fallthrough to default case. 48691cb0ef41Sopenharmony_ci // TODO(ignition): Add debug code to check that {resume_mode} really is 48701cb0ef41Sopenharmony_ci // {JSGeneratorObject::kNext} in this case. 48711cb0ef41Sopenharmony_ci STATIC_ASSERT(JSGeneratorObject::kNext == 0); 48721cb0ef41Sopenharmony_ci { 48731cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddCallICSlot(); 48741cb0ef41Sopenharmony_ci builder()->CallProperty(iterator.next(), iterator_and_input, 48751cb0ef41Sopenharmony_ci feedback_index(slot)); 48761cb0ef41Sopenharmony_ci builder()->Jump(after_switch.New()); 48771cb0ef41Sopenharmony_ci } 48781cb0ef41Sopenharmony_ci 48791cb0ef41Sopenharmony_ci STATIC_ASSERT(JSGeneratorObject::kReturn == 1); 48801cb0ef41Sopenharmony_ci builder()->Bind(switch_jump_table, JSGeneratorObject::kReturn); 48811cb0ef41Sopenharmony_ci { 48821cb0ef41Sopenharmony_ci const AstRawString* return_string = 48831cb0ef41Sopenharmony_ci ast_string_constants()->return_string(); 48841cb0ef41Sopenharmony_ci BytecodeLabels no_return_method(zone()); 48851cb0ef41Sopenharmony_ci 48861cb0ef41Sopenharmony_ci BuildCallIteratorMethod(iterator.object(), return_string, 48871cb0ef41Sopenharmony_ci iterator_and_input, after_switch.New(), 48881cb0ef41Sopenharmony_ci &no_return_method); 48891cb0ef41Sopenharmony_ci no_return_method.Bind(builder()); 48901cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(input); 48911cb0ef41Sopenharmony_ci if (iterator_type == IteratorType::kAsync) { 48921cb0ef41Sopenharmony_ci // Await input. 48931cb0ef41Sopenharmony_ci BuildAwait(expr->position()); 48941cb0ef41Sopenharmony_ci execution_control()->AsyncReturnAccumulator(kNoSourcePosition); 48951cb0ef41Sopenharmony_ci } else { 48961cb0ef41Sopenharmony_ci execution_control()->ReturnAccumulator(kNoSourcePosition); 48971cb0ef41Sopenharmony_ci } 48981cb0ef41Sopenharmony_ci } 48991cb0ef41Sopenharmony_ci 49001cb0ef41Sopenharmony_ci STATIC_ASSERT(JSGeneratorObject::kThrow == 2); 49011cb0ef41Sopenharmony_ci builder()->Bind(switch_jump_table, JSGeneratorObject::kThrow); 49021cb0ef41Sopenharmony_ci { 49031cb0ef41Sopenharmony_ci const AstRawString* throw_string = 49041cb0ef41Sopenharmony_ci ast_string_constants()->throw_string(); 49051cb0ef41Sopenharmony_ci BytecodeLabels no_throw_method(zone()); 49061cb0ef41Sopenharmony_ci BuildCallIteratorMethod(iterator.object(), throw_string, 49071cb0ef41Sopenharmony_ci iterator_and_input, after_switch.New(), 49081cb0ef41Sopenharmony_ci &no_throw_method); 49091cb0ef41Sopenharmony_ci 49101cb0ef41Sopenharmony_ci // If there is no "throw" method, perform IteratorClose, and finally 49111cb0ef41Sopenharmony_ci // throw a TypeError. 49121cb0ef41Sopenharmony_ci no_throw_method.Bind(builder()); 49131cb0ef41Sopenharmony_ci BuildIteratorClose(iterator, expr); 49141cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kThrowThrowMethodMissing); 49151cb0ef41Sopenharmony_ci } 49161cb0ef41Sopenharmony_ci 49171cb0ef41Sopenharmony_ci after_switch.Bind(builder()); 49181cb0ef41Sopenharmony_ci } 49191cb0ef41Sopenharmony_ci 49201cb0ef41Sopenharmony_ci if (iterator_type == IteratorType::kAsync) { 49211cb0ef41Sopenharmony_ci // Await the result of the method invocation. 49221cb0ef41Sopenharmony_ci BuildAwait(expr->position()); 49231cb0ef41Sopenharmony_ci } 49241cb0ef41Sopenharmony_ci 49251cb0ef41Sopenharmony_ci // Check that output is an object. 49261cb0ef41Sopenharmony_ci BytecodeLabel check_if_done; 49271cb0ef41Sopenharmony_ci builder() 49281cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(output) 49291cb0ef41Sopenharmony_ci .JumpIfJSReceiver(&check_if_done) 49301cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, output); 49311cb0ef41Sopenharmony_ci 49321cb0ef41Sopenharmony_ci builder()->Bind(&check_if_done); 49331cb0ef41Sopenharmony_ci // Break once output.done is true. 49341cb0ef41Sopenharmony_ci builder()->LoadNamedProperty( 49351cb0ef41Sopenharmony_ci output, ast_string_constants()->done_string(), 49361cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLoadICSlot())); 49371cb0ef41Sopenharmony_ci 49381cb0ef41Sopenharmony_ci loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean); 49391cb0ef41Sopenharmony_ci 49401cb0ef41Sopenharmony_ci // Suspend the current generator. 49411cb0ef41Sopenharmony_ci if (iterator_type == IteratorType::kNormal) { 49421cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(output); 49431cb0ef41Sopenharmony_ci } else { 49441cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 49451cb0ef41Sopenharmony_ci DCHECK_EQ(iterator_type, IteratorType::kAsync); 49461cb0ef41Sopenharmony_ci // If generatorKind is async, perform AsyncGeneratorYield(output.value), 49471cb0ef41Sopenharmony_ci // which will await `output.value` before resolving the current 49481cb0ef41Sopenharmony_ci // AsyncGeneratorRequest's promise. 49491cb0ef41Sopenharmony_ci builder()->LoadNamedProperty( 49501cb0ef41Sopenharmony_ci output, ast_string_constants()->value_string(), 49511cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLoadICSlot())); 49521cb0ef41Sopenharmony_ci 49531cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(3); 49541cb0ef41Sopenharmony_ci builder() 49551cb0ef41Sopenharmony_ci ->MoveRegister(generator_object(), args[0]) // generator 49561cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) // value 49571cb0ef41Sopenharmony_ci .LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT) 49581cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[2]) // is_caught 49591cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kInlineAsyncGeneratorYield, args); 49601cb0ef41Sopenharmony_ci } 49611cb0ef41Sopenharmony_ci 49621cb0ef41Sopenharmony_ci BuildSuspendPoint(expr->position()); 49631cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(input); 49641cb0ef41Sopenharmony_ci builder() 49651cb0ef41Sopenharmony_ci ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, 49661cb0ef41Sopenharmony_ci generator_object()) 49671cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(resume_mode); 49681cb0ef41Sopenharmony_ci 49691cb0ef41Sopenharmony_ci loop_builder.BindContinueTarget(); 49701cb0ef41Sopenharmony_ci } 49711cb0ef41Sopenharmony_ci } 49721cb0ef41Sopenharmony_ci 49731cb0ef41Sopenharmony_ci // Decide if we trigger a return or if the yield* expression should just 49741cb0ef41Sopenharmony_ci // produce a value. 49751cb0ef41Sopenharmony_ci BytecodeLabel completion_is_output_value; 49761cb0ef41Sopenharmony_ci Register output_value = register_allocator()->NewRegister(); 49771cb0ef41Sopenharmony_ci builder() 49781cb0ef41Sopenharmony_ci ->LoadNamedProperty(output, ast_string_constants()->value_string(), 49791cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLoadICSlot())) 49801cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(output_value) 49811cb0ef41Sopenharmony_ci .LoadLiteral(Smi::FromInt(JSGeneratorObject::kReturn)) 49821cb0ef41Sopenharmony_ci .CompareReference(resume_mode) 49831cb0ef41Sopenharmony_ci .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &completion_is_output_value) 49841cb0ef41Sopenharmony_ci .LoadAccumulatorWithRegister(output_value); 49851cb0ef41Sopenharmony_ci if (iterator_type == IteratorType::kAsync) { 49861cb0ef41Sopenharmony_ci execution_control()->AsyncReturnAccumulator(kNoSourcePosition); 49871cb0ef41Sopenharmony_ci } else { 49881cb0ef41Sopenharmony_ci execution_control()->ReturnAccumulator(kNoSourcePosition); 49891cb0ef41Sopenharmony_ci } 49901cb0ef41Sopenharmony_ci 49911cb0ef41Sopenharmony_ci builder()->Bind(&completion_is_output_value); 49921cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(expr, 49931cb0ef41Sopenharmony_ci SourceRangeKind::kContinuation); 49941cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(output_value); 49951cb0ef41Sopenharmony_ci} 49961cb0ef41Sopenharmony_ci 49971cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildAwait(int position) { 49981cb0ef41Sopenharmony_ci // Rather than HandlerTable::UNCAUGHT, async functions use 49991cb0ef41Sopenharmony_ci // HandlerTable::ASYNC_AWAIT to communicate that top-level exceptions are 50001cb0ef41Sopenharmony_ci // transformed into promise rejections. This is necessary to prevent emitting 50011cb0ef41Sopenharmony_ci // multiple debug events for the same uncaught exception. There is no point 50021cb0ef41Sopenharmony_ci // in the body of an async function where catch prediction is 50031cb0ef41Sopenharmony_ci // HandlerTable::UNCAUGHT. 50041cb0ef41Sopenharmony_ci DCHECK(catch_prediction() != HandlerTable::UNCAUGHT || 50051cb0ef41Sopenharmony_ci info()->scope()->is_repl_mode_scope()); 50061cb0ef41Sopenharmony_ci 50071cb0ef41Sopenharmony_ci { 50081cb0ef41Sopenharmony_ci // Await(operand) and suspend. 50091cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 50101cb0ef41Sopenharmony_ci 50111cb0ef41Sopenharmony_ci Runtime::FunctionId await_intrinsic_id; 50121cb0ef41Sopenharmony_ci if (IsAsyncGeneratorFunction(function_kind())) { 50131cb0ef41Sopenharmony_ci await_intrinsic_id = catch_prediction() == HandlerTable::ASYNC_AWAIT 50141cb0ef41Sopenharmony_ci ? Runtime::kInlineAsyncGeneratorAwaitUncaught 50151cb0ef41Sopenharmony_ci : Runtime::kInlineAsyncGeneratorAwaitCaught; 50161cb0ef41Sopenharmony_ci } else { 50171cb0ef41Sopenharmony_ci await_intrinsic_id = catch_prediction() == HandlerTable::ASYNC_AWAIT 50181cb0ef41Sopenharmony_ci ? Runtime::kInlineAsyncFunctionAwaitUncaught 50191cb0ef41Sopenharmony_ci : Runtime::kInlineAsyncFunctionAwaitCaught; 50201cb0ef41Sopenharmony_ci } 50211cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 50221cb0ef41Sopenharmony_ci builder() 50231cb0ef41Sopenharmony_ci ->MoveRegister(generator_object(), args[0]) 50241cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) 50251cb0ef41Sopenharmony_ci .CallRuntime(await_intrinsic_id, args); 50261cb0ef41Sopenharmony_ci } 50271cb0ef41Sopenharmony_ci 50281cb0ef41Sopenharmony_ci BuildSuspendPoint(position); 50291cb0ef41Sopenharmony_ci 50301cb0ef41Sopenharmony_ci Register input = register_allocator()->NewRegister(); 50311cb0ef41Sopenharmony_ci Register resume_mode = register_allocator()->NewRegister(); 50321cb0ef41Sopenharmony_ci 50331cb0ef41Sopenharmony_ci // Now dispatch on resume mode. 50341cb0ef41Sopenharmony_ci BytecodeLabel resume_next; 50351cb0ef41Sopenharmony_ci builder() 50361cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(input) 50371cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator_object()) 50381cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(resume_mode) 50391cb0ef41Sopenharmony_ci .LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) 50401cb0ef41Sopenharmony_ci .CompareReference(resume_mode) 50411cb0ef41Sopenharmony_ci .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_next); 50421cb0ef41Sopenharmony_ci 50431cb0ef41Sopenharmony_ci // Resume with "throw" completion (rethrow the received value). 50441cb0ef41Sopenharmony_ci // TODO(leszeks): Add a debug-only check that the accumulator is 50451cb0ef41Sopenharmony_ci // JSGeneratorObject::kThrow. 50461cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(input).ReThrow(); 50471cb0ef41Sopenharmony_ci 50481cb0ef41Sopenharmony_ci // Resume with next. 50491cb0ef41Sopenharmony_ci builder()->Bind(&resume_next); 50501cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(input); 50511cb0ef41Sopenharmony_ci} 50521cb0ef41Sopenharmony_ci 50531cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitAwait(Await* expr) { 50541cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 50551cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->expression()); 50561cb0ef41Sopenharmony_ci BuildAwait(expr->position()); 50571cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(expr, 50581cb0ef41Sopenharmony_ci SourceRangeKind::kContinuation); 50591cb0ef41Sopenharmony_ci} 50601cb0ef41Sopenharmony_ci 50611cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitThrow(Throw* expr) { 50621cb0ef41Sopenharmony_ci AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kContinuation); 50631cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->exception()); 50641cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 50651cb0ef41Sopenharmony_ci builder()->Throw(); 50661cb0ef41Sopenharmony_ci} 50671cb0ef41Sopenharmony_ci 50681cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) { 50691cb0ef41Sopenharmony_ci if (property->is_optional_chain_link()) { 50701cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(optional_chaining_null_labels_); 50711cb0ef41Sopenharmony_ci int right_range = 50721cb0ef41Sopenharmony_ci AllocateBlockCoverageSlotIfEnabled(property, SourceRangeKind::kRight); 50731cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(obj).JumpIfUndefinedOrNull( 50741cb0ef41Sopenharmony_ci optional_chaining_null_labels_->New()); 50751cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(right_range); 50761cb0ef41Sopenharmony_ci } 50771cb0ef41Sopenharmony_ci 50781cb0ef41Sopenharmony_ci AssignType property_kind = Property::GetAssignType(property); 50791cb0ef41Sopenharmony_ci 50801cb0ef41Sopenharmony_ci switch (property_kind) { 50811cb0ef41Sopenharmony_ci case NON_PROPERTY: 50821cb0ef41Sopenharmony_ci UNREACHABLE(); 50831cb0ef41Sopenharmony_ci case NAMED_PROPERTY: { 50841cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property); 50851cb0ef41Sopenharmony_ci const AstRawString* name = 50861cb0ef41Sopenharmony_ci property->key()->AsLiteral()->AsRawPropertyName(); 50871cb0ef41Sopenharmony_ci BuildLoadNamedProperty(property->obj(), obj, name); 50881cb0ef41Sopenharmony_ci break; 50891cb0ef41Sopenharmony_ci } 50901cb0ef41Sopenharmony_ci case KEYED_PROPERTY: { 50911cb0ef41Sopenharmony_ci VisitForAccumulatorValue(property->key()); 50921cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property); 50931cb0ef41Sopenharmony_ci builder()->LoadKeyedProperty( 50941cb0ef41Sopenharmony_ci obj, feedback_index(feedback_spec()->AddKeyedLoadICSlot())); 50951cb0ef41Sopenharmony_ci break; 50961cb0ef41Sopenharmony_ci } 50971cb0ef41Sopenharmony_ci case NAMED_SUPER_PROPERTY: 50981cb0ef41Sopenharmony_ci VisitNamedSuperPropertyLoad(property, Register::invalid_value()); 50991cb0ef41Sopenharmony_ci break; 51001cb0ef41Sopenharmony_ci case KEYED_SUPER_PROPERTY: 51011cb0ef41Sopenharmony_ci VisitKeyedSuperPropertyLoad(property, Register::invalid_value()); 51021cb0ef41Sopenharmony_ci break; 51031cb0ef41Sopenharmony_ci case PRIVATE_SETTER_ONLY: { 51041cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, obj); 51051cb0ef41Sopenharmony_ci BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateGetterAccess, 51061cb0ef41Sopenharmony_ci property); 51071cb0ef41Sopenharmony_ci break; 51081cb0ef41Sopenharmony_ci } 51091cb0ef41Sopenharmony_ci case PRIVATE_GETTER_ONLY: 51101cb0ef41Sopenharmony_ci case PRIVATE_GETTER_AND_SETTER: { 51111cb0ef41Sopenharmony_ci Register key = VisitForRegisterValue(property->key()); 51121cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, obj); 51131cb0ef41Sopenharmony_ci BuildPrivateGetterAccess(obj, key); 51141cb0ef41Sopenharmony_ci break; 51151cb0ef41Sopenharmony_ci } 51161cb0ef41Sopenharmony_ci case PRIVATE_METHOD: { 51171cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, obj); 51181cb0ef41Sopenharmony_ci // In the case of private methods, property->key() is the function to be 51191cb0ef41Sopenharmony_ci // loaded (stored in a context slot), so load this directly. 51201cb0ef41Sopenharmony_ci VisitForAccumulatorValue(property->key()); 51211cb0ef41Sopenharmony_ci break; 51221cb0ef41Sopenharmony_ci } 51231cb0ef41Sopenharmony_ci } 51241cb0ef41Sopenharmony_ci} 51251cb0ef41Sopenharmony_ci 51261cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildPrivateGetterAccess(Register object, 51271cb0ef41Sopenharmony_ci Register accessor_pair) { 51281cb0ef41Sopenharmony_ci RegisterAllocationScope scope(this); 51291cb0ef41Sopenharmony_ci Register accessor = register_allocator()->NewRegister(); 51301cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(1); 51311cb0ef41Sopenharmony_ci 51321cb0ef41Sopenharmony_ci builder() 51331cb0ef41Sopenharmony_ci ->CallRuntime(Runtime::kLoadPrivateGetter, accessor_pair) 51341cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(accessor) 51351cb0ef41Sopenharmony_ci .MoveRegister(object, args[0]) 51361cb0ef41Sopenharmony_ci .CallProperty(accessor, args, 51371cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot())); 51381cb0ef41Sopenharmony_ci} 51391cb0ef41Sopenharmony_ci 51401cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildPrivateSetterAccess(Register object, 51411cb0ef41Sopenharmony_ci Register accessor_pair, 51421cb0ef41Sopenharmony_ci Register value) { 51431cb0ef41Sopenharmony_ci RegisterAllocationScope scope(this); 51441cb0ef41Sopenharmony_ci Register accessor = register_allocator()->NewRegister(); 51451cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 51461cb0ef41Sopenharmony_ci 51471cb0ef41Sopenharmony_ci builder() 51481cb0ef41Sopenharmony_ci ->CallRuntime(Runtime::kLoadPrivateSetter, accessor_pair) 51491cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(accessor) 51501cb0ef41Sopenharmony_ci .MoveRegister(object, args[0]) 51511cb0ef41Sopenharmony_ci .MoveRegister(value, args[1]) 51521cb0ef41Sopenharmony_ci .CallProperty(accessor, args, 51531cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot())); 51541cb0ef41Sopenharmony_ci} 51551cb0ef41Sopenharmony_ci 51561cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildPrivateMethodIn(Variable* private_name, 51571cb0ef41Sopenharmony_ci Expression* object_expression) { 51581cb0ef41Sopenharmony_ci DCHECK(IsPrivateMethodOrAccessorVariableMode(private_name->mode())); 51591cb0ef41Sopenharmony_ci ClassScope* scope = private_name->scope()->AsClassScope(); 51601cb0ef41Sopenharmony_ci if (private_name->is_static()) { 51611cb0ef41Sopenharmony_ci // For static private methods, "#privatemethod in ..." only returns true for 51621cb0ef41Sopenharmony_ci // the class constructor. 51631cb0ef41Sopenharmony_ci if (scope->class_variable() == nullptr) { 51641cb0ef41Sopenharmony_ci // Can only happen via the debugger. See comment in 51651cb0ef41Sopenharmony_ci // BuildPrivateBrandCheck. 51661cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 51671cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 51681cb0ef41Sopenharmony_ci builder() 51691cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromEnum( 51701cb0ef41Sopenharmony_ci MessageTemplate:: 51711cb0ef41Sopenharmony_ci kInvalidUnusedPrivateStaticMethodAccessedByDebugger)) 51721cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[0]) 51731cb0ef41Sopenharmony_ci .LoadLiteral(private_name->raw_name()) 51741cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) 51751cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kNewError, args) 51761cb0ef41Sopenharmony_ci .Throw(); 51771cb0ef41Sopenharmony_ci } else { 51781cb0ef41Sopenharmony_ci VisitForAccumulatorValue(object_expression); 51791cb0ef41Sopenharmony_ci Register object = register_allocator()->NewRegister(); 51801cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(object); 51811cb0ef41Sopenharmony_ci 51821cb0ef41Sopenharmony_ci BytecodeLabel is_object; 51831cb0ef41Sopenharmony_ci builder()->JumpIfJSReceiver(&is_object); 51841cb0ef41Sopenharmony_ci 51851cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(3); 51861cb0ef41Sopenharmony_ci builder() 51871cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(args[2]) 51881cb0ef41Sopenharmony_ci .LoadLiteral(Smi::FromEnum(MessageTemplate::kInvalidInOperatorUse)) 51891cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[0]) 51901cb0ef41Sopenharmony_ci .LoadLiteral(private_name->raw_name()) 51911cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) 51921cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kNewTypeError, args) 51931cb0ef41Sopenharmony_ci .Throw(); 51941cb0ef41Sopenharmony_ci 51951cb0ef41Sopenharmony_ci builder()->Bind(&is_object); 51961cb0ef41Sopenharmony_ci BuildVariableLoadForAccumulatorValue(scope->class_variable(), 51971cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 51981cb0ef41Sopenharmony_ci builder()->CompareReference(object); 51991cb0ef41Sopenharmony_ci } 52001cb0ef41Sopenharmony_ci } else { 52011cb0ef41Sopenharmony_ci BuildVariableLoadForAccumulatorValue(scope->brand(), 52021cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 52031cb0ef41Sopenharmony_ci Register brand = register_allocator()->NewRegister(); 52041cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(brand); 52051cb0ef41Sopenharmony_ci 52061cb0ef41Sopenharmony_ci VisitForAccumulatorValue(object_expression); 52071cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(object_expression); 52081cb0ef41Sopenharmony_ci 52091cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddKeyedHasICSlot(); 52101cb0ef41Sopenharmony_ci builder()->CompareOperation(Token::IN, brand, feedback_index(slot)); 52111cb0ef41Sopenharmony_ci execution_result()->SetResultIsBoolean(); 52121cb0ef41Sopenharmony_ci } 52131cb0ef41Sopenharmony_ci} 52141cb0ef41Sopenharmony_ci 52151cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildPrivateBrandCheck(Property* property, 52161cb0ef41Sopenharmony_ci Register object) { 52171cb0ef41Sopenharmony_ci Variable* private_name = property->key()->AsVariableProxy()->var(); 52181cb0ef41Sopenharmony_ci DCHECK(IsPrivateMethodOrAccessorVariableMode(private_name->mode())); 52191cb0ef41Sopenharmony_ci ClassScope* scope = private_name->scope()->AsClassScope(); 52201cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property); 52211cb0ef41Sopenharmony_ci if (private_name->is_static()) { 52221cb0ef41Sopenharmony_ci // For static private methods, the only valid receiver is the class. 52231cb0ef41Sopenharmony_ci // Load the class constructor. 52241cb0ef41Sopenharmony_ci if (scope->class_variable() == nullptr) { 52251cb0ef41Sopenharmony_ci // If the static private method has not been used used in source 52261cb0ef41Sopenharmony_ci // code (either explicitly or through the presence of eval), but is 52271cb0ef41Sopenharmony_ci // accessed by the debugger at runtime, reference to the class variable 52281cb0ef41Sopenharmony_ci // is not available since it was not be context-allocated. Therefore we 52291cb0ef41Sopenharmony_ci // can't build a branch check, and throw an ReferenceError as if the 52301cb0ef41Sopenharmony_ci // method was optimized away. 52311cb0ef41Sopenharmony_ci // TODO(joyee): get a reference to the class constructor through 52321cb0ef41Sopenharmony_ci // something other than scope->class_variable() in this scenario. 52331cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 52341cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 52351cb0ef41Sopenharmony_ci builder() 52361cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromEnum( 52371cb0ef41Sopenharmony_ci MessageTemplate:: 52381cb0ef41Sopenharmony_ci kInvalidUnusedPrivateStaticMethodAccessedByDebugger)) 52391cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[0]) 52401cb0ef41Sopenharmony_ci .LoadLiteral(private_name->raw_name()) 52411cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) 52421cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kNewError, args) 52431cb0ef41Sopenharmony_ci .Throw(); 52441cb0ef41Sopenharmony_ci } else { 52451cb0ef41Sopenharmony_ci BuildVariableLoadForAccumulatorValue(scope->class_variable(), 52461cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 52471cb0ef41Sopenharmony_ci BytecodeLabel return_check; 52481cb0ef41Sopenharmony_ci builder()->CompareReference(object).JumpIfTrue( 52491cb0ef41Sopenharmony_ci ToBooleanMode::kAlreadyBoolean, &return_check); 52501cb0ef41Sopenharmony_ci const AstRawString* name = scope->class_variable()->raw_name(); 52511cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 52521cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 52531cb0ef41Sopenharmony_ci builder() 52541cb0ef41Sopenharmony_ci ->LoadLiteral( 52551cb0ef41Sopenharmony_ci Smi::FromEnum(MessageTemplate::kInvalidPrivateBrandStatic)) 52561cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[0]) 52571cb0ef41Sopenharmony_ci .LoadLiteral(name) 52581cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[1]) 52591cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kNewTypeError, args) 52601cb0ef41Sopenharmony_ci .Throw(); 52611cb0ef41Sopenharmony_ci builder()->Bind(&return_check); 52621cb0ef41Sopenharmony_ci } 52631cb0ef41Sopenharmony_ci } else { 52641cb0ef41Sopenharmony_ci BuildVariableLoadForAccumulatorValue(scope->brand(), 52651cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 52661cb0ef41Sopenharmony_ci builder()->LoadKeyedProperty( 52671cb0ef41Sopenharmony_ci object, feedback_index(feedback_spec()->AddKeyedLoadICSlot())); 52681cb0ef41Sopenharmony_ci } 52691cb0ef41Sopenharmony_ci} 52701cb0ef41Sopenharmony_ci 52711cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitPropertyLoadForRegister(Register obj, 52721cb0ef41Sopenharmony_ci Property* expr, 52731cb0ef41Sopenharmony_ci Register destination) { 52741cb0ef41Sopenharmony_ci ValueResultScope result_scope(this); 52751cb0ef41Sopenharmony_ci VisitPropertyLoad(obj, expr); 52761cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(destination); 52771cb0ef41Sopenharmony_ci} 52781cb0ef41Sopenharmony_ci 52791cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property, 52801cb0ef41Sopenharmony_ci Register opt_receiver_out) { 52811cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 52821cb0ef41Sopenharmony_ci if (FLAG_super_ic) { 52831cb0ef41Sopenharmony_ci Register receiver = register_allocator()->NewRegister(); 52841cb0ef41Sopenharmony_ci BuildThisVariableLoad(); 52851cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(receiver); 52861cb0ef41Sopenharmony_ci BuildVariableLoad( 52871cb0ef41Sopenharmony_ci property->obj()->AsSuperPropertyReference()->home_object()->var(), 52881cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 52891cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property); 52901cb0ef41Sopenharmony_ci auto name = property->key()->AsLiteral()->AsRawPropertyName(); 52911cb0ef41Sopenharmony_ci FeedbackSlot slot = GetCachedLoadSuperICSlot(name); 52921cb0ef41Sopenharmony_ci builder()->LoadNamedPropertyFromSuper(receiver, name, feedback_index(slot)); 52931cb0ef41Sopenharmony_ci if (opt_receiver_out.is_valid()) { 52941cb0ef41Sopenharmony_ci builder()->MoveRegister(receiver, opt_receiver_out); 52951cb0ef41Sopenharmony_ci } 52961cb0ef41Sopenharmony_ci } else { 52971cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(3); 52981cb0ef41Sopenharmony_ci BuildThisVariableLoad(); 52991cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(args[0]); 53001cb0ef41Sopenharmony_ci BuildVariableLoad( 53011cb0ef41Sopenharmony_ci property->obj()->AsSuperPropertyReference()->home_object()->var(), 53021cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 53031cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(args[1]); 53041cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property); 53051cb0ef41Sopenharmony_ci builder() 53061cb0ef41Sopenharmony_ci ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 53071cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(args[2]) 53081cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kLoadFromSuper, args); 53091cb0ef41Sopenharmony_ci 53101cb0ef41Sopenharmony_ci if (opt_receiver_out.is_valid()) { 53111cb0ef41Sopenharmony_ci builder()->MoveRegister(args[0], opt_receiver_out); 53121cb0ef41Sopenharmony_ci } 53131cb0ef41Sopenharmony_ci } 53141cb0ef41Sopenharmony_ci} 53151cb0ef41Sopenharmony_ci 53161cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property, 53171cb0ef41Sopenharmony_ci Register opt_receiver_out) { 53181cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 53191cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(3); 53201cb0ef41Sopenharmony_ci BuildThisVariableLoad(); 53211cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(args[0]); 53221cb0ef41Sopenharmony_ci BuildVariableLoad( 53231cb0ef41Sopenharmony_ci property->obj()->AsSuperPropertyReference()->home_object()->var(), 53241cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 53251cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(args[1]); 53261cb0ef41Sopenharmony_ci VisitForRegisterValue(property->key(), args[2]); 53271cb0ef41Sopenharmony_ci 53281cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(property); 53291cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, args); 53301cb0ef41Sopenharmony_ci 53311cb0ef41Sopenharmony_ci if (opt_receiver_out.is_valid()) { 53321cb0ef41Sopenharmony_ci builder()->MoveRegister(args[0], opt_receiver_out); 53331cb0ef41Sopenharmony_ci } 53341cb0ef41Sopenharmony_ci} 53351cb0ef41Sopenharmony_ci 53361cb0ef41Sopenharmony_citemplate <typename ExpressionFunc> 53371cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildOptionalChain(ExpressionFunc expression_func) { 53381cb0ef41Sopenharmony_ci BytecodeLabel done; 53391cb0ef41Sopenharmony_ci OptionalChainNullLabelScope label_scope(this); 53401cb0ef41Sopenharmony_ci expression_func(); 53411cb0ef41Sopenharmony_ci builder()->Jump(&done); 53421cb0ef41Sopenharmony_ci label_scope.labels()->Bind(builder()); 53431cb0ef41Sopenharmony_ci builder()->LoadUndefined(); 53441cb0ef41Sopenharmony_ci builder()->Bind(&done); 53451cb0ef41Sopenharmony_ci} 53461cb0ef41Sopenharmony_ci 53471cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitOptionalChain(OptionalChain* expr) { 53481cb0ef41Sopenharmony_ci BuildOptionalChain([&]() { VisitForAccumulatorValue(expr->expression()); }); 53491cb0ef41Sopenharmony_ci} 53501cb0ef41Sopenharmony_ci 53511cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitProperty(Property* expr) { 53521cb0ef41Sopenharmony_ci AssignType property_kind = Property::GetAssignType(expr); 53531cb0ef41Sopenharmony_ci if (property_kind != NAMED_SUPER_PROPERTY && 53541cb0ef41Sopenharmony_ci property_kind != KEYED_SUPER_PROPERTY) { 53551cb0ef41Sopenharmony_ci Register obj = VisitForRegisterValue(expr->obj()); 53561cb0ef41Sopenharmony_ci VisitPropertyLoad(obj, expr); 53571cb0ef41Sopenharmony_ci } else { 53581cb0ef41Sopenharmony_ci VisitPropertyLoad(Register::invalid_value(), expr); 53591cb0ef41Sopenharmony_ci } 53601cb0ef41Sopenharmony_ci} 53611cb0ef41Sopenharmony_ci 53621cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitArguments(const ZonePtrList<Expression>* args, 53631cb0ef41Sopenharmony_ci RegisterList* arg_regs) { 53641cb0ef41Sopenharmony_ci // Visit arguments. 53651cb0ef41Sopenharmony_ci for (int i = 0; i < static_cast<int>(args->length()); i++) { 53661cb0ef41Sopenharmony_ci VisitAndPushIntoRegisterList(args->at(i), arg_regs); 53671cb0ef41Sopenharmony_ci } 53681cb0ef41Sopenharmony_ci} 53691cb0ef41Sopenharmony_ci 53701cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitCall(Call* expr) { 53711cb0ef41Sopenharmony_ci Expression* callee_expr = expr->expression(); 53721cb0ef41Sopenharmony_ci Call::CallType call_type = expr->GetCallType(); 53731cb0ef41Sopenharmony_ci 53741cb0ef41Sopenharmony_ci if (call_type == Call::SUPER_CALL) { 53751cb0ef41Sopenharmony_ci return VisitCallSuper(expr); 53761cb0ef41Sopenharmony_ci } 53771cb0ef41Sopenharmony_ci 53781cb0ef41Sopenharmony_ci // We compile the call differently depending on the presence of spreads and 53791cb0ef41Sopenharmony_ci // their positions. 53801cb0ef41Sopenharmony_ci // 53811cb0ef41Sopenharmony_ci // If there is only one spread and it is the final argument, there is a 53821cb0ef41Sopenharmony_ci // special CallWithSpread bytecode. 53831cb0ef41Sopenharmony_ci // 53841cb0ef41Sopenharmony_ci // If there is a non-final spread, we rewrite calls like 53851cb0ef41Sopenharmony_ci // callee(1, ...x, 2) 53861cb0ef41Sopenharmony_ci // to 53871cb0ef41Sopenharmony_ci // %reflect_apply(callee, receiver, [1, ...x, 2]) 53881cb0ef41Sopenharmony_ci const Call::SpreadPosition spread_position = expr->spread_position(); 53891cb0ef41Sopenharmony_ci 53901cb0ef41Sopenharmony_ci // Grow the args list as we visit receiver / arguments to avoid allocating all 53911cb0ef41Sopenharmony_ci // the registers up-front. Otherwise these registers are unavailable during 53921cb0ef41Sopenharmony_ci // receiver / argument visiting and we can end up with memory leaks due to 53931cb0ef41Sopenharmony_ci // registers keeping objects alive. 53941cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewGrowableRegisterList(); 53951cb0ef41Sopenharmony_ci 53961cb0ef41Sopenharmony_ci // The callee is the first register in args for ease of calling %reflect_apply 53971cb0ef41Sopenharmony_ci // if we have a non-final spread. For all other cases it is popped from args 53981cb0ef41Sopenharmony_ci // before emitting the call below. 53991cb0ef41Sopenharmony_ci Register callee = register_allocator()->GrowRegisterList(&args); 54001cb0ef41Sopenharmony_ci 54011cb0ef41Sopenharmony_ci bool implicit_undefined_receiver = false; 54021cb0ef41Sopenharmony_ci 54031cb0ef41Sopenharmony_ci // TODO(petermarshall): We have a lot of call bytecodes that are very similar, 54041cb0ef41Sopenharmony_ci // see if we can reduce the number by adding a separate argument which 54051cb0ef41Sopenharmony_ci // specifies the call type (e.g., property, spread, tailcall, etc.). 54061cb0ef41Sopenharmony_ci 54071cb0ef41Sopenharmony_ci // Prepare the callee and the receiver to the function call. This depends on 54081cb0ef41Sopenharmony_ci // the semantics of the underlying call type. 54091cb0ef41Sopenharmony_ci switch (call_type) { 54101cb0ef41Sopenharmony_ci case Call::NAMED_PROPERTY_CALL: 54111cb0ef41Sopenharmony_ci case Call::KEYED_PROPERTY_CALL: 54121cb0ef41Sopenharmony_ci case Call::PRIVATE_CALL: { 54131cb0ef41Sopenharmony_ci Property* property = callee_expr->AsProperty(); 54141cb0ef41Sopenharmony_ci VisitAndPushIntoRegisterList(property->obj(), &args); 54151cb0ef41Sopenharmony_ci VisitPropertyLoadForRegister(args.last_register(), property, callee); 54161cb0ef41Sopenharmony_ci break; 54171cb0ef41Sopenharmony_ci } 54181cb0ef41Sopenharmony_ci case Call::GLOBAL_CALL: { 54191cb0ef41Sopenharmony_ci // Receiver is undefined for global calls. 54201cb0ef41Sopenharmony_ci if (spread_position == Call::kNoSpread) { 54211cb0ef41Sopenharmony_ci implicit_undefined_receiver = true; 54221cb0ef41Sopenharmony_ci } else { 54231cb0ef41Sopenharmony_ci // TODO(leszeks): There's no special bytecode for tail calls or spread 54241cb0ef41Sopenharmony_ci // calls with an undefined receiver, so just push undefined ourselves. 54251cb0ef41Sopenharmony_ci BuildPushUndefinedIntoRegisterList(&args); 54261cb0ef41Sopenharmony_ci } 54271cb0ef41Sopenharmony_ci // Load callee as a global variable. 54281cb0ef41Sopenharmony_ci VariableProxy* proxy = callee_expr->AsVariableProxy(); 54291cb0ef41Sopenharmony_ci BuildVariableLoadForAccumulatorValue(proxy->var(), 54301cb0ef41Sopenharmony_ci proxy->hole_check_mode()); 54311cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(callee); 54321cb0ef41Sopenharmony_ci break; 54331cb0ef41Sopenharmony_ci } 54341cb0ef41Sopenharmony_ci case Call::WITH_CALL: { 54351cb0ef41Sopenharmony_ci Register receiver = register_allocator()->GrowRegisterList(&args); 54361cb0ef41Sopenharmony_ci DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot()); 54371cb0ef41Sopenharmony_ci { 54381cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 54391cb0ef41Sopenharmony_ci Register name = register_allocator()->NewRegister(); 54401cb0ef41Sopenharmony_ci 54411cb0ef41Sopenharmony_ci // Call %LoadLookupSlotForCall to get the callee and receiver. 54421cb0ef41Sopenharmony_ci RegisterList result_pair = register_allocator()->NewRegisterList(2); 54431cb0ef41Sopenharmony_ci Variable* variable = callee_expr->AsVariableProxy()->var(); 54441cb0ef41Sopenharmony_ci builder() 54451cb0ef41Sopenharmony_ci ->LoadLiteral(variable->raw_name()) 54461cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(name) 54471cb0ef41Sopenharmony_ci .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name, 54481cb0ef41Sopenharmony_ci result_pair) 54491cb0ef41Sopenharmony_ci .MoveRegister(result_pair[0], callee) 54501cb0ef41Sopenharmony_ci .MoveRegister(result_pair[1], receiver); 54511cb0ef41Sopenharmony_ci } 54521cb0ef41Sopenharmony_ci break; 54531cb0ef41Sopenharmony_ci } 54541cb0ef41Sopenharmony_ci case Call::OTHER_CALL: { 54551cb0ef41Sopenharmony_ci // Receiver is undefined for other calls. 54561cb0ef41Sopenharmony_ci if (spread_position == Call::kNoSpread) { 54571cb0ef41Sopenharmony_ci implicit_undefined_receiver = true; 54581cb0ef41Sopenharmony_ci } else { 54591cb0ef41Sopenharmony_ci // TODO(leszeks): There's no special bytecode for tail calls or spread 54601cb0ef41Sopenharmony_ci // calls with an undefined receiver, so just push undefined ourselves. 54611cb0ef41Sopenharmony_ci BuildPushUndefinedIntoRegisterList(&args); 54621cb0ef41Sopenharmony_ci } 54631cb0ef41Sopenharmony_ci VisitForRegisterValue(callee_expr, callee); 54641cb0ef41Sopenharmony_ci break; 54651cb0ef41Sopenharmony_ci } 54661cb0ef41Sopenharmony_ci case Call::NAMED_SUPER_PROPERTY_CALL: { 54671cb0ef41Sopenharmony_ci Register receiver = register_allocator()->GrowRegisterList(&args); 54681cb0ef41Sopenharmony_ci Property* property = callee_expr->AsProperty(); 54691cb0ef41Sopenharmony_ci VisitNamedSuperPropertyLoad(property, receiver); 54701cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(callee); 54711cb0ef41Sopenharmony_ci break; 54721cb0ef41Sopenharmony_ci } 54731cb0ef41Sopenharmony_ci case Call::KEYED_SUPER_PROPERTY_CALL: { 54741cb0ef41Sopenharmony_ci Register receiver = register_allocator()->GrowRegisterList(&args); 54751cb0ef41Sopenharmony_ci Property* property = callee_expr->AsProperty(); 54761cb0ef41Sopenharmony_ci VisitKeyedSuperPropertyLoad(property, receiver); 54771cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(callee); 54781cb0ef41Sopenharmony_ci break; 54791cb0ef41Sopenharmony_ci } 54801cb0ef41Sopenharmony_ci case Call::NAMED_OPTIONAL_CHAIN_PROPERTY_CALL: 54811cb0ef41Sopenharmony_ci case Call::KEYED_OPTIONAL_CHAIN_PROPERTY_CALL: 54821cb0ef41Sopenharmony_ci case Call::PRIVATE_OPTIONAL_CHAIN_CALL: { 54831cb0ef41Sopenharmony_ci OptionalChain* chain = callee_expr->AsOptionalChain(); 54841cb0ef41Sopenharmony_ci Property* property = chain->expression()->AsProperty(); 54851cb0ef41Sopenharmony_ci BuildOptionalChain([&]() { 54861cb0ef41Sopenharmony_ci VisitAndPushIntoRegisterList(property->obj(), &args); 54871cb0ef41Sopenharmony_ci VisitPropertyLoad(args.last_register(), property); 54881cb0ef41Sopenharmony_ci }); 54891cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(callee); 54901cb0ef41Sopenharmony_ci break; 54911cb0ef41Sopenharmony_ci } 54921cb0ef41Sopenharmony_ci case Call::SUPER_CALL: 54931cb0ef41Sopenharmony_ci UNREACHABLE(); 54941cb0ef41Sopenharmony_ci } 54951cb0ef41Sopenharmony_ci 54961cb0ef41Sopenharmony_ci if (expr->is_optional_chain_link()) { 54971cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(optional_chaining_null_labels_); 54981cb0ef41Sopenharmony_ci int right_range = 54991cb0ef41Sopenharmony_ci AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kRight); 55001cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(callee).JumpIfUndefinedOrNull( 55011cb0ef41Sopenharmony_ci optional_chaining_null_labels_->New()); 55021cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(right_range); 55031cb0ef41Sopenharmony_ci } 55041cb0ef41Sopenharmony_ci 55051cb0ef41Sopenharmony_ci int receiver_arg_count = -1; 55061cb0ef41Sopenharmony_ci if (spread_position == Call::kHasNonFinalSpread) { 55071cb0ef41Sopenharmony_ci // If we're building %reflect_apply, build the array literal and put it in 55081cb0ef41Sopenharmony_ci // the 3rd argument. 55091cb0ef41Sopenharmony_ci DCHECK(!implicit_undefined_receiver); 55101cb0ef41Sopenharmony_ci DCHECK_EQ(args.register_count(), 2); 55111cb0ef41Sopenharmony_ci BuildCreateArrayLiteral(expr->arguments(), nullptr); 55121cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister( 55131cb0ef41Sopenharmony_ci register_allocator()->GrowRegisterList(&args)); 55141cb0ef41Sopenharmony_ci } else { 55151cb0ef41Sopenharmony_ci // If we're not building %reflect_apply and don't need to build an array 55161cb0ef41Sopenharmony_ci // literal, pop the callee and evaluate all arguments to the function call 55171cb0ef41Sopenharmony_ci // and store in sequential args registers. 55181cb0ef41Sopenharmony_ci args = args.PopLeft(); 55191cb0ef41Sopenharmony_ci VisitArguments(expr->arguments(), &args); 55201cb0ef41Sopenharmony_ci receiver_arg_count = implicit_undefined_receiver ? 0 : 1; 55211cb0ef41Sopenharmony_ci CHECK_EQ(receiver_arg_count + expr->arguments()->length(), 55221cb0ef41Sopenharmony_ci args.register_count()); 55231cb0ef41Sopenharmony_ci } 55241cb0ef41Sopenharmony_ci 55251cb0ef41Sopenharmony_ci // Resolve callee for a potential direct eval call. This block will mutate the 55261cb0ef41Sopenharmony_ci // callee value. 55271cb0ef41Sopenharmony_ci if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { 55281cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 55291cb0ef41Sopenharmony_ci RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); 55301cb0ef41Sopenharmony_ci // Set up arguments for ResolvePossiblyDirectEval by copying callee, source 55311cb0ef41Sopenharmony_ci // strings and function closure, and loading language and 55321cb0ef41Sopenharmony_ci // position. 55331cb0ef41Sopenharmony_ci 55341cb0ef41Sopenharmony_ci // Move the first arg. 55351cb0ef41Sopenharmony_ci if (spread_position == Call::kHasNonFinalSpread) { 55361cb0ef41Sopenharmony_ci int feedback_slot_index = 55371cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddKeyedLoadICSlot()); 55381cb0ef41Sopenharmony_ci Register args_array = args[2]; 55391cb0ef41Sopenharmony_ci builder() 55401cb0ef41Sopenharmony_ci ->LoadLiteral(Smi::FromInt(0)) 55411cb0ef41Sopenharmony_ci .LoadKeyedProperty(args_array, feedback_slot_index) 55421cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(runtime_call_args[1]); 55431cb0ef41Sopenharmony_ci } else { 55441cb0ef41Sopenharmony_ci // FIXME(v8:5690): Support final spreads for eval. 55451cb0ef41Sopenharmony_ci DCHECK_GE(receiver_arg_count, 0); 55461cb0ef41Sopenharmony_ci builder()->MoveRegister(args[receiver_arg_count], runtime_call_args[1]); 55471cb0ef41Sopenharmony_ci } 55481cb0ef41Sopenharmony_ci builder() 55491cb0ef41Sopenharmony_ci ->MoveRegister(callee, runtime_call_args[0]) 55501cb0ef41Sopenharmony_ci .MoveRegister(Register::function_closure(), runtime_call_args[2]) 55511cb0ef41Sopenharmony_ci .LoadLiteral(Smi::FromEnum(language_mode())) 55521cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(runtime_call_args[3]) 55531cb0ef41Sopenharmony_ci .LoadLiteral(Smi::FromInt(current_scope()->start_position())) 55541cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(runtime_call_args[4]) 55551cb0ef41Sopenharmony_ci .LoadLiteral(Smi::FromInt(expr->position())) 55561cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(runtime_call_args[5]); 55571cb0ef41Sopenharmony_ci 55581cb0ef41Sopenharmony_ci // Call ResolvePossiblyDirectEval and modify the callee. 55591cb0ef41Sopenharmony_ci builder() 55601cb0ef41Sopenharmony_ci ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args) 55611cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(callee); 55621cb0ef41Sopenharmony_ci } 55631cb0ef41Sopenharmony_ci 55641cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 55651cb0ef41Sopenharmony_ci 55661cb0ef41Sopenharmony_ci if (spread_position == Call::kHasFinalSpread) { 55671cb0ef41Sopenharmony_ci DCHECK(!implicit_undefined_receiver); 55681cb0ef41Sopenharmony_ci builder()->CallWithSpread(callee, args, 55691cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot())); 55701cb0ef41Sopenharmony_ci } else if (spread_position == Call::kHasNonFinalSpread) { 55711cb0ef41Sopenharmony_ci builder()->CallJSRuntime(Context::REFLECT_APPLY_INDEX, args); 55721cb0ef41Sopenharmony_ci } else if (call_type == Call::NAMED_PROPERTY_CALL || 55731cb0ef41Sopenharmony_ci call_type == Call::KEYED_PROPERTY_CALL) { 55741cb0ef41Sopenharmony_ci DCHECK(!implicit_undefined_receiver); 55751cb0ef41Sopenharmony_ci builder()->CallProperty(callee, args, 55761cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot())); 55771cb0ef41Sopenharmony_ci } else if (implicit_undefined_receiver) { 55781cb0ef41Sopenharmony_ci builder()->CallUndefinedReceiver( 55791cb0ef41Sopenharmony_ci callee, args, feedback_index(feedback_spec()->AddCallICSlot())); 55801cb0ef41Sopenharmony_ci } else { 55811cb0ef41Sopenharmony_ci builder()->CallAnyReceiver( 55821cb0ef41Sopenharmony_ci callee, args, feedback_index(feedback_spec()->AddCallICSlot())); 55831cb0ef41Sopenharmony_ci } 55841cb0ef41Sopenharmony_ci} 55851cb0ef41Sopenharmony_ci 55861cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitCallSuper(Call* expr) { 55871cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 55881cb0ef41Sopenharmony_ci SuperCallReference* super = expr->expression()->AsSuperCallReference(); 55891cb0ef41Sopenharmony_ci const ZonePtrList<Expression>* args = expr->arguments(); 55901cb0ef41Sopenharmony_ci 55911cb0ef41Sopenharmony_ci // We compile the super call differently depending on the presence of spreads 55921cb0ef41Sopenharmony_ci // and their positions. 55931cb0ef41Sopenharmony_ci // 55941cb0ef41Sopenharmony_ci // If there is only one spread and it is the final argument, there is a 55951cb0ef41Sopenharmony_ci // special ConstructWithSpread bytecode. 55961cb0ef41Sopenharmony_ci // 55971cb0ef41Sopenharmony_ci // It there is a non-final spread, we rewrite something like 55981cb0ef41Sopenharmony_ci // super(1, ...x, 2) 55991cb0ef41Sopenharmony_ci // to 56001cb0ef41Sopenharmony_ci // %reflect_construct(constructor, [1, ...x, 2], new_target) 56011cb0ef41Sopenharmony_ci // 56021cb0ef41Sopenharmony_ci // That is, we implement (non-last-arg) spreads in super calls via our 56031cb0ef41Sopenharmony_ci // mechanism for spreads in array literals. 56041cb0ef41Sopenharmony_ci const Call::SpreadPosition spread_position = expr->spread_position(); 56051cb0ef41Sopenharmony_ci 56061cb0ef41Sopenharmony_ci // Prepare the constructor to the super call. 56071cb0ef41Sopenharmony_ci Register this_function = VisitForRegisterValue(super->this_function_var()); 56081cb0ef41Sopenharmony_ci Register constructor = register_allocator()->NewRegister(); 56091cb0ef41Sopenharmony_ci builder() 56101cb0ef41Sopenharmony_ci ->LoadAccumulatorWithRegister(this_function) 56111cb0ef41Sopenharmony_ci .GetSuperConstructor(constructor); 56121cb0ef41Sopenharmony_ci 56131cb0ef41Sopenharmony_ci if (spread_position == Call::kHasNonFinalSpread) { 56141cb0ef41Sopenharmony_ci // First generate the array containing all arguments. 56151cb0ef41Sopenharmony_ci BuildCreateArrayLiteral(args, nullptr); 56161cb0ef41Sopenharmony_ci 56171cb0ef41Sopenharmony_ci // Check if the constructor is in fact a constructor. 56181cb0ef41Sopenharmony_ci builder()->ThrowIfNotSuperConstructor(constructor); 56191cb0ef41Sopenharmony_ci 56201cb0ef41Sopenharmony_ci // Now pass that array to %reflect_construct. 56211cb0ef41Sopenharmony_ci RegisterList construct_args = register_allocator()->NewRegisterList(3); 56221cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(construct_args[1]); 56231cb0ef41Sopenharmony_ci builder()->MoveRegister(constructor, construct_args[0]); 56241cb0ef41Sopenharmony_ci VisitForRegisterValue(super->new_target_var(), construct_args[2]); 56251cb0ef41Sopenharmony_ci builder()->CallJSRuntime(Context::REFLECT_CONSTRUCT_INDEX, construct_args); 56261cb0ef41Sopenharmony_ci } else { 56271cb0ef41Sopenharmony_ci RegisterList args_regs = register_allocator()->NewGrowableRegisterList(); 56281cb0ef41Sopenharmony_ci VisitArguments(args, &args_regs); 56291cb0ef41Sopenharmony_ci 56301cb0ef41Sopenharmony_ci // Check if the constructor is in fact a constructor. 56311cb0ef41Sopenharmony_ci builder()->ThrowIfNotSuperConstructor(constructor); 56321cb0ef41Sopenharmony_ci 56331cb0ef41Sopenharmony_ci // The new target is loaded into the accumulator from the 56341cb0ef41Sopenharmony_ci // {new.target} variable. 56351cb0ef41Sopenharmony_ci VisitForAccumulatorValue(super->new_target_var()); 56361cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 56371cb0ef41Sopenharmony_ci 56381cb0ef41Sopenharmony_ci int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot()); 56391cb0ef41Sopenharmony_ci 56401cb0ef41Sopenharmony_ci if (spread_position == Call::kHasFinalSpread) { 56411cb0ef41Sopenharmony_ci builder()->ConstructWithSpread(constructor, args_regs, 56421cb0ef41Sopenharmony_ci feedback_slot_index); 56431cb0ef41Sopenharmony_ci } else { 56441cb0ef41Sopenharmony_ci DCHECK_EQ(spread_position, Call::kNoSpread); 56451cb0ef41Sopenharmony_ci // Call construct. 56461cb0ef41Sopenharmony_ci // TODO(turbofan): For now we do gather feedback on super constructor 56471cb0ef41Sopenharmony_ci // calls, utilizing the existing machinery to inline the actual call 56481cb0ef41Sopenharmony_ci // target and the JSCreate for the implicit receiver allocation. This 56491cb0ef41Sopenharmony_ci // is not an ideal solution for super constructor calls, but it gets 56501cb0ef41Sopenharmony_ci // the job done for now. In the long run we might want to revisit this 56511cb0ef41Sopenharmony_ci // and come up with a better way. 56521cb0ef41Sopenharmony_ci builder()->Construct(constructor, args_regs, feedback_slot_index); 56531cb0ef41Sopenharmony_ci } 56541cb0ef41Sopenharmony_ci } 56551cb0ef41Sopenharmony_ci 56561cb0ef41Sopenharmony_ci // Explicit calls to the super constructor using super() perform an 56571cb0ef41Sopenharmony_ci // implicit binding assignment to the 'this' variable. 56581cb0ef41Sopenharmony_ci // 56591cb0ef41Sopenharmony_ci // Default constructors don't need have to do the assignment because 56601cb0ef41Sopenharmony_ci // 'this' isn't accessed in default constructors. 56611cb0ef41Sopenharmony_ci if (!IsDefaultConstructor(info()->literal()->kind())) { 56621cb0ef41Sopenharmony_ci Variable* var = closure_scope()->GetReceiverScope()->receiver(); 56631cb0ef41Sopenharmony_ci BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kRequired); 56641cb0ef41Sopenharmony_ci } 56651cb0ef41Sopenharmony_ci 56661cb0ef41Sopenharmony_ci Register instance = register_allocator()->NewRegister(); 56671cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(instance); 56681cb0ef41Sopenharmony_ci 56691cb0ef41Sopenharmony_ci // The constructor scope always needs ScopeInfo, so we are certain that 56701cb0ef41Sopenharmony_ci // the first constructor scope found in the outer scope chain is the 56711cb0ef41Sopenharmony_ci // scope that we are looking for for this super() call. 56721cb0ef41Sopenharmony_ci // Note that this doesn't necessarily mean that the constructor needs 56731cb0ef41Sopenharmony_ci // a context, if it doesn't this would get handled specially in 56741cb0ef41Sopenharmony_ci // BuildPrivateBrandInitialization(). 56751cb0ef41Sopenharmony_ci DeclarationScope* constructor_scope = info()->scope()->GetConstructorScope(); 56761cb0ef41Sopenharmony_ci 56771cb0ef41Sopenharmony_ci // We can rely on the class_scope_has_private_brand bit to tell if the 56781cb0ef41Sopenharmony_ci // constructor needs private brand initialization, and if that's 56791cb0ef41Sopenharmony_ci // the case we are certain that its outer class scope requires a context to 56801cb0ef41Sopenharmony_ci // keep the brand variable, so we can just get the brand variable 56811cb0ef41Sopenharmony_ci // from the outer scope. 56821cb0ef41Sopenharmony_ci if (constructor_scope->class_scope_has_private_brand()) { 56831cb0ef41Sopenharmony_ci DCHECK(constructor_scope->outer_scope()->is_class_scope()); 56841cb0ef41Sopenharmony_ci ClassScope* class_scope = constructor_scope->outer_scope()->AsClassScope(); 56851cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(class_scope->brand()); 56861cb0ef41Sopenharmony_ci Variable* brand = class_scope->brand(); 56871cb0ef41Sopenharmony_ci BuildPrivateBrandInitialization(instance, brand); 56881cb0ef41Sopenharmony_ci } 56891cb0ef41Sopenharmony_ci 56901cb0ef41Sopenharmony_ci // The derived constructor has the correct bit set always, so we 56911cb0ef41Sopenharmony_ci // don't emit code to load and call the initializer if not 56921cb0ef41Sopenharmony_ci // required. 56931cb0ef41Sopenharmony_ci // 56941cb0ef41Sopenharmony_ci // For the arrow function or eval case, we always emit code to load 56951cb0ef41Sopenharmony_ci // and call the initializer. 56961cb0ef41Sopenharmony_ci // 56971cb0ef41Sopenharmony_ci // TODO(gsathya): In the future, we could tag nested arrow functions 56981cb0ef41Sopenharmony_ci // or eval with the correct bit so that we do the load conditionally 56991cb0ef41Sopenharmony_ci // if required. 57001cb0ef41Sopenharmony_ci if (info()->literal()->requires_instance_members_initializer() || 57011cb0ef41Sopenharmony_ci !IsDerivedConstructor(info()->literal()->kind())) { 57021cb0ef41Sopenharmony_ci BuildInstanceMemberInitialization(this_function, instance); 57031cb0ef41Sopenharmony_ci } 57041cb0ef41Sopenharmony_ci 57051cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(instance); 57061cb0ef41Sopenharmony_ci} 57071cb0ef41Sopenharmony_ci 57081cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitCallNew(CallNew* expr) { 57091cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewGrowableRegisterList(); 57101cb0ef41Sopenharmony_ci 57111cb0ef41Sopenharmony_ci // Load the constructor. It's in the first register in args for ease of 57121cb0ef41Sopenharmony_ci // calling %reflect_construct if we have a non-final spread. For all other 57131cb0ef41Sopenharmony_ci // cases it is popped before emitting the construct below. 57141cb0ef41Sopenharmony_ci VisitAndPushIntoRegisterList(expr->expression(), &args); 57151cb0ef41Sopenharmony_ci 57161cb0ef41Sopenharmony_ci // We compile the new differently depending on the presence of spreads and 57171cb0ef41Sopenharmony_ci // their positions. 57181cb0ef41Sopenharmony_ci // 57191cb0ef41Sopenharmony_ci // If there is only one spread and it is the final argument, there is a 57201cb0ef41Sopenharmony_ci // special ConstructWithSpread bytecode. 57211cb0ef41Sopenharmony_ci // 57221cb0ef41Sopenharmony_ci // If there is a non-final spread, we rewrite calls like 57231cb0ef41Sopenharmony_ci // new ctor(1, ...x, 2) 57241cb0ef41Sopenharmony_ci // to 57251cb0ef41Sopenharmony_ci // %reflect_construct(ctor, [1, ...x, 2]) 57261cb0ef41Sopenharmony_ci const CallNew::SpreadPosition spread_position = expr->spread_position(); 57271cb0ef41Sopenharmony_ci 57281cb0ef41Sopenharmony_ci if (spread_position == CallNew::kHasNonFinalSpread) { 57291cb0ef41Sopenharmony_ci BuildCreateArrayLiteral(expr->arguments(), nullptr); 57301cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 57311cb0ef41Sopenharmony_ci builder() 57321cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister( 57331cb0ef41Sopenharmony_ci register_allocator()->GrowRegisterList(&args)) 57341cb0ef41Sopenharmony_ci .CallJSRuntime(Context::REFLECT_CONSTRUCT_INDEX, args); 57351cb0ef41Sopenharmony_ci return; 57361cb0ef41Sopenharmony_ci } 57371cb0ef41Sopenharmony_ci 57381cb0ef41Sopenharmony_ci Register constructor = args.first_register(); 57391cb0ef41Sopenharmony_ci args = args.PopLeft(); 57401cb0ef41Sopenharmony_ci VisitArguments(expr->arguments(), &args); 57411cb0ef41Sopenharmony_ci 57421cb0ef41Sopenharmony_ci // The accumulator holds new target which is the same as the 57431cb0ef41Sopenharmony_ci // constructor for CallNew. 57441cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 57451cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(constructor); 57461cb0ef41Sopenharmony_ci 57471cb0ef41Sopenharmony_ci int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot()); 57481cb0ef41Sopenharmony_ci if (spread_position == CallNew::kHasFinalSpread) { 57491cb0ef41Sopenharmony_ci builder()->ConstructWithSpread(constructor, args, feedback_slot_index); 57501cb0ef41Sopenharmony_ci } else { 57511cb0ef41Sopenharmony_ci DCHECK_EQ(spread_position, CallNew::kNoSpread); 57521cb0ef41Sopenharmony_ci builder()->Construct(constructor, args, feedback_slot_index); 57531cb0ef41Sopenharmony_ci } 57541cb0ef41Sopenharmony_ci} 57551cb0ef41Sopenharmony_ci 57561cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { 57571cb0ef41Sopenharmony_ci if (expr->is_jsruntime()) { 57581cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewGrowableRegisterList(); 57591cb0ef41Sopenharmony_ci VisitArguments(expr->arguments(), &args); 57601cb0ef41Sopenharmony_ci builder()->CallJSRuntime(expr->context_index(), args); 57611cb0ef41Sopenharmony_ci } else { 57621cb0ef41Sopenharmony_ci // Evaluate all arguments to the runtime call. 57631cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewGrowableRegisterList(); 57641cb0ef41Sopenharmony_ci VisitArguments(expr->arguments(), &args); 57651cb0ef41Sopenharmony_ci Runtime::FunctionId function_id = expr->function()->function_id; 57661cb0ef41Sopenharmony_ci builder()->CallRuntime(function_id, args); 57671cb0ef41Sopenharmony_ci } 57681cb0ef41Sopenharmony_ci} 57691cb0ef41Sopenharmony_ci 57701cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitVoid(UnaryOperation* expr) { 57711cb0ef41Sopenharmony_ci VisitForEffect(expr->expression()); 57721cb0ef41Sopenharmony_ci builder()->LoadUndefined(); 57731cb0ef41Sopenharmony_ci} 57741cb0ef41Sopenharmony_ci 57751cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitForTypeOfValue(Expression* expr) { 57761cb0ef41Sopenharmony_ci if (expr->IsVariableProxy()) { 57771cb0ef41Sopenharmony_ci // Typeof does not throw a reference error on global variables, hence we 57781cb0ef41Sopenharmony_ci // perform a non-contextual load in case the operand is a variable proxy. 57791cb0ef41Sopenharmony_ci VariableProxy* proxy = expr->AsVariableProxy(); 57801cb0ef41Sopenharmony_ci BuildVariableLoadForAccumulatorValue(proxy->var(), proxy->hole_check_mode(), 57811cb0ef41Sopenharmony_ci TypeofMode::kInside); 57821cb0ef41Sopenharmony_ci } else { 57831cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr); 57841cb0ef41Sopenharmony_ci } 57851cb0ef41Sopenharmony_ci} 57861cb0ef41Sopenharmony_ci 57871cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { 57881cb0ef41Sopenharmony_ci VisitForTypeOfValue(expr->expression()); 57891cb0ef41Sopenharmony_ci builder()->TypeOf(); 57901cb0ef41Sopenharmony_ci} 57911cb0ef41Sopenharmony_ci 57921cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNot(UnaryOperation* expr) { 57931cb0ef41Sopenharmony_ci if (execution_result()->IsEffect()) { 57941cb0ef41Sopenharmony_ci VisitForEffect(expr->expression()); 57951cb0ef41Sopenharmony_ci } else if (execution_result()->IsTest()) { 57961cb0ef41Sopenharmony_ci // No actual logical negation happening, we just swap the control flow, by 57971cb0ef41Sopenharmony_ci // swapping the target labels and the fallthrough branch, and visit in the 57981cb0ef41Sopenharmony_ci // same test result context. 57991cb0ef41Sopenharmony_ci TestResultScope* test_result = execution_result()->AsTest(); 58001cb0ef41Sopenharmony_ci test_result->InvertControlFlow(); 58011cb0ef41Sopenharmony_ci VisitInSameTestExecutionScope(expr->expression()); 58021cb0ef41Sopenharmony_ci } else { 58031cb0ef41Sopenharmony_ci TypeHint type_hint = VisitForAccumulatorValue(expr->expression()); 58041cb0ef41Sopenharmony_ci builder()->LogicalNot(ToBooleanModeFromTypeHint(type_hint)); 58051cb0ef41Sopenharmony_ci // Always returns a boolean value. 58061cb0ef41Sopenharmony_ci execution_result()->SetResultIsBoolean(); 58071cb0ef41Sopenharmony_ci } 58081cb0ef41Sopenharmony_ci} 58091cb0ef41Sopenharmony_ci 58101cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 58111cb0ef41Sopenharmony_ci switch (expr->op()) { 58121cb0ef41Sopenharmony_ci case Token::Value::NOT: 58131cb0ef41Sopenharmony_ci VisitNot(expr); 58141cb0ef41Sopenharmony_ci break; 58151cb0ef41Sopenharmony_ci case Token::Value::TYPEOF: 58161cb0ef41Sopenharmony_ci VisitTypeOf(expr); 58171cb0ef41Sopenharmony_ci break; 58181cb0ef41Sopenharmony_ci case Token::Value::VOID: 58191cb0ef41Sopenharmony_ci VisitVoid(expr); 58201cb0ef41Sopenharmony_ci break; 58211cb0ef41Sopenharmony_ci case Token::Value::DELETE: 58221cb0ef41Sopenharmony_ci VisitDelete(expr); 58231cb0ef41Sopenharmony_ci break; 58241cb0ef41Sopenharmony_ci case Token::Value::ADD: 58251cb0ef41Sopenharmony_ci case Token::Value::SUB: 58261cb0ef41Sopenharmony_ci case Token::Value::BIT_NOT: 58271cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->expression()); 58281cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 58291cb0ef41Sopenharmony_ci builder()->UnaryOperation( 58301cb0ef41Sopenharmony_ci expr->op(), feedback_index(feedback_spec()->AddBinaryOpICSlot())); 58311cb0ef41Sopenharmony_ci break; 58321cb0ef41Sopenharmony_ci default: 58331cb0ef41Sopenharmony_ci UNREACHABLE(); 58341cb0ef41Sopenharmony_ci } 58351cb0ef41Sopenharmony_ci} 58361cb0ef41Sopenharmony_ci 58371cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitDelete(UnaryOperation* unary) { 58381cb0ef41Sopenharmony_ci Expression* expr = unary->expression(); 58391cb0ef41Sopenharmony_ci if (expr->IsProperty()) { 58401cb0ef41Sopenharmony_ci // Delete of an object property is allowed both in sloppy 58411cb0ef41Sopenharmony_ci // and strict modes. 58421cb0ef41Sopenharmony_ci Property* property = expr->AsProperty(); 58431cb0ef41Sopenharmony_ci DCHECK(!property->IsPrivateReference()); 58441cb0ef41Sopenharmony_ci Register object = VisitForRegisterValue(property->obj()); 58451cb0ef41Sopenharmony_ci VisitForAccumulatorValue(property->key()); 58461cb0ef41Sopenharmony_ci builder()->Delete(object, language_mode()); 58471cb0ef41Sopenharmony_ci } else if (expr->IsOptionalChain()) { 58481cb0ef41Sopenharmony_ci Expression* expr_inner = expr->AsOptionalChain()->expression(); 58491cb0ef41Sopenharmony_ci if (expr_inner->IsProperty()) { 58501cb0ef41Sopenharmony_ci Property* property = expr_inner->AsProperty(); 58511cb0ef41Sopenharmony_ci DCHECK(!property->IsPrivateReference()); 58521cb0ef41Sopenharmony_ci BytecodeLabel done; 58531cb0ef41Sopenharmony_ci OptionalChainNullLabelScope label_scope(this); 58541cb0ef41Sopenharmony_ci VisitForAccumulatorValue(property->obj()); 58551cb0ef41Sopenharmony_ci if (property->is_optional_chain_link()) { 58561cb0ef41Sopenharmony_ci int right_range = AllocateBlockCoverageSlotIfEnabled( 58571cb0ef41Sopenharmony_ci property, SourceRangeKind::kRight); 58581cb0ef41Sopenharmony_ci builder()->JumpIfUndefinedOrNull(label_scope.labels()->New()); 58591cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(right_range); 58601cb0ef41Sopenharmony_ci } 58611cb0ef41Sopenharmony_ci Register object = register_allocator()->NewRegister(); 58621cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(object); 58631cb0ef41Sopenharmony_ci VisitForAccumulatorValue(property->key()); 58641cb0ef41Sopenharmony_ci builder()->Delete(object, language_mode()); 58651cb0ef41Sopenharmony_ci builder()->Jump(&done); 58661cb0ef41Sopenharmony_ci label_scope.labels()->Bind(builder()); 58671cb0ef41Sopenharmony_ci builder()->LoadTrue(); 58681cb0ef41Sopenharmony_ci builder()->Bind(&done); 58691cb0ef41Sopenharmony_ci } else { 58701cb0ef41Sopenharmony_ci VisitForEffect(expr); 58711cb0ef41Sopenharmony_ci builder()->LoadTrue(); 58721cb0ef41Sopenharmony_ci } 58731cb0ef41Sopenharmony_ci } else if (expr->IsVariableProxy() && 58741cb0ef41Sopenharmony_ci !expr->AsVariableProxy()->is_new_target()) { 58751cb0ef41Sopenharmony_ci // Delete of an unqualified identifier is allowed in sloppy mode but is 58761cb0ef41Sopenharmony_ci // not allowed in strict mode. 58771cb0ef41Sopenharmony_ci DCHECK(is_sloppy(language_mode())); 58781cb0ef41Sopenharmony_ci Variable* variable = expr->AsVariableProxy()->var(); 58791cb0ef41Sopenharmony_ci switch (variable->location()) { 58801cb0ef41Sopenharmony_ci case VariableLocation::PARAMETER: 58811cb0ef41Sopenharmony_ci case VariableLocation::LOCAL: 58821cb0ef41Sopenharmony_ci case VariableLocation::CONTEXT: 58831cb0ef41Sopenharmony_ci case VariableLocation::REPL_GLOBAL: { 58841cb0ef41Sopenharmony_ci // Deleting local var/let/const, context variables, and arguments 58851cb0ef41Sopenharmony_ci // does not have any effect. 58861cb0ef41Sopenharmony_ci builder()->LoadFalse(); 58871cb0ef41Sopenharmony_ci break; 58881cb0ef41Sopenharmony_ci } 58891cb0ef41Sopenharmony_ci case VariableLocation::UNALLOCATED: 58901cb0ef41Sopenharmony_ci // TODO(adamk): Falling through to the runtime results in correct 58911cb0ef41Sopenharmony_ci // behavior, but does unnecessary context-walking (since scope 58921cb0ef41Sopenharmony_ci // analysis has already proven that the variable doesn't exist in 58931cb0ef41Sopenharmony_ci // any non-global scope). Consider adding a DeleteGlobal bytecode 58941cb0ef41Sopenharmony_ci // that knows how to deal with ScriptContexts as well as global 58951cb0ef41Sopenharmony_ci // object properties. 58961cb0ef41Sopenharmony_ci case VariableLocation::LOOKUP: { 58971cb0ef41Sopenharmony_ci Register name_reg = register_allocator()->NewRegister(); 58981cb0ef41Sopenharmony_ci builder() 58991cb0ef41Sopenharmony_ci ->LoadLiteral(variable->raw_name()) 59001cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(name_reg) 59011cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kDeleteLookupSlot, name_reg); 59021cb0ef41Sopenharmony_ci break; 59031cb0ef41Sopenharmony_ci } 59041cb0ef41Sopenharmony_ci case VariableLocation::MODULE: 59051cb0ef41Sopenharmony_ci // Modules are always in strict mode and unqualified identifers are not 59061cb0ef41Sopenharmony_ci // allowed in strict mode. 59071cb0ef41Sopenharmony_ci UNREACHABLE(); 59081cb0ef41Sopenharmony_ci } 59091cb0ef41Sopenharmony_ci } else { 59101cb0ef41Sopenharmony_ci // Delete of an unresolvable reference, new.target, and this returns true. 59111cb0ef41Sopenharmony_ci VisitForEffect(expr); 59121cb0ef41Sopenharmony_ci builder()->LoadTrue(); 59131cb0ef41Sopenharmony_ci } 59141cb0ef41Sopenharmony_ci} 59151cb0ef41Sopenharmony_ci 59161cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitCountOperation(CountOperation* expr) { 59171cb0ef41Sopenharmony_ci DCHECK(expr->expression()->IsValidReferenceExpression()); 59181cb0ef41Sopenharmony_ci 59191cb0ef41Sopenharmony_ci // Left-hand side can only be a property, a global or a variable slot. 59201cb0ef41Sopenharmony_ci Property* property = expr->expression()->AsProperty(); 59211cb0ef41Sopenharmony_ci AssignType assign_type = Property::GetAssignType(property); 59221cb0ef41Sopenharmony_ci 59231cb0ef41Sopenharmony_ci bool is_postfix = expr->is_postfix() && !execution_result()->IsEffect(); 59241cb0ef41Sopenharmony_ci 59251cb0ef41Sopenharmony_ci // Evaluate LHS expression and get old value. 59261cb0ef41Sopenharmony_ci Register object, key, old_value; 59271cb0ef41Sopenharmony_ci RegisterList super_property_args; 59281cb0ef41Sopenharmony_ci const AstRawString* name; 59291cb0ef41Sopenharmony_ci switch (assign_type) { 59301cb0ef41Sopenharmony_ci case NON_PROPERTY: { 59311cb0ef41Sopenharmony_ci VariableProxy* proxy = expr->expression()->AsVariableProxy(); 59321cb0ef41Sopenharmony_ci BuildVariableLoadForAccumulatorValue(proxy->var(), 59331cb0ef41Sopenharmony_ci proxy->hole_check_mode()); 59341cb0ef41Sopenharmony_ci break; 59351cb0ef41Sopenharmony_ci } 59361cb0ef41Sopenharmony_ci case NAMED_PROPERTY: { 59371cb0ef41Sopenharmony_ci object = VisitForRegisterValue(property->obj()); 59381cb0ef41Sopenharmony_ci name = property->key()->AsLiteral()->AsRawPropertyName(); 59391cb0ef41Sopenharmony_ci builder()->LoadNamedProperty( 59401cb0ef41Sopenharmony_ci object, name, 59411cb0ef41Sopenharmony_ci feedback_index(GetCachedLoadICSlot(property->obj(), name))); 59421cb0ef41Sopenharmony_ci break; 59431cb0ef41Sopenharmony_ci } 59441cb0ef41Sopenharmony_ci case KEYED_PROPERTY: { 59451cb0ef41Sopenharmony_ci object = VisitForRegisterValue(property->obj()); 59461cb0ef41Sopenharmony_ci // Use visit for accumulator here since we need the key in the accumulator 59471cb0ef41Sopenharmony_ci // for the LoadKeyedProperty. 59481cb0ef41Sopenharmony_ci key = register_allocator()->NewRegister(); 59491cb0ef41Sopenharmony_ci VisitForAccumulatorValue(property->key()); 59501cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty( 59511cb0ef41Sopenharmony_ci object, feedback_index(feedback_spec()->AddKeyedLoadICSlot())); 59521cb0ef41Sopenharmony_ci break; 59531cb0ef41Sopenharmony_ci } 59541cb0ef41Sopenharmony_ci case NAMED_SUPER_PROPERTY: { 59551cb0ef41Sopenharmony_ci super_property_args = register_allocator()->NewRegisterList(4); 59561cb0ef41Sopenharmony_ci RegisterList load_super_args = super_property_args.Truncate(3); 59571cb0ef41Sopenharmony_ci BuildThisVariableLoad(); 59581cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(load_super_args[0]); 59591cb0ef41Sopenharmony_ci BuildVariableLoad( 59601cb0ef41Sopenharmony_ci property->obj()->AsSuperPropertyReference()->home_object()->var(), 59611cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 59621cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(load_super_args[1]); 59631cb0ef41Sopenharmony_ci builder() 59641cb0ef41Sopenharmony_ci ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) 59651cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(load_super_args[2]) 59661cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kLoadFromSuper, load_super_args); 59671cb0ef41Sopenharmony_ci break; 59681cb0ef41Sopenharmony_ci } 59691cb0ef41Sopenharmony_ci case KEYED_SUPER_PROPERTY: { 59701cb0ef41Sopenharmony_ci super_property_args = register_allocator()->NewRegisterList(4); 59711cb0ef41Sopenharmony_ci RegisterList load_super_args = super_property_args.Truncate(3); 59721cb0ef41Sopenharmony_ci BuildThisVariableLoad(); 59731cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(load_super_args[0]); 59741cb0ef41Sopenharmony_ci BuildVariableLoad( 59751cb0ef41Sopenharmony_ci property->obj()->AsSuperPropertyReference()->home_object()->var(), 59761cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 59771cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(load_super_args[1]); 59781cb0ef41Sopenharmony_ci VisitForRegisterValue(property->key(), load_super_args[2]); 59791cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args); 59801cb0ef41Sopenharmony_ci break; 59811cb0ef41Sopenharmony_ci } 59821cb0ef41Sopenharmony_ci case PRIVATE_METHOD: { 59831cb0ef41Sopenharmony_ci object = VisitForRegisterValue(property->obj()); 59841cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, object); 59851cb0ef41Sopenharmony_ci BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateMethodWrite, 59861cb0ef41Sopenharmony_ci property); 59871cb0ef41Sopenharmony_ci return; 59881cb0ef41Sopenharmony_ci } 59891cb0ef41Sopenharmony_ci case PRIVATE_GETTER_ONLY: { 59901cb0ef41Sopenharmony_ci object = VisitForRegisterValue(property->obj()); 59911cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, object); 59921cb0ef41Sopenharmony_ci BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateSetterAccess, 59931cb0ef41Sopenharmony_ci property); 59941cb0ef41Sopenharmony_ci return; 59951cb0ef41Sopenharmony_ci } 59961cb0ef41Sopenharmony_ci case PRIVATE_SETTER_ONLY: { 59971cb0ef41Sopenharmony_ci object = VisitForRegisterValue(property->obj()); 59981cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, object); 59991cb0ef41Sopenharmony_ci BuildInvalidPropertyAccess(MessageTemplate::kInvalidPrivateGetterAccess, 60001cb0ef41Sopenharmony_ci property); 60011cb0ef41Sopenharmony_ci return; 60021cb0ef41Sopenharmony_ci } 60031cb0ef41Sopenharmony_ci case PRIVATE_GETTER_AND_SETTER: { 60041cb0ef41Sopenharmony_ci object = VisitForRegisterValue(property->obj()); 60051cb0ef41Sopenharmony_ci key = VisitForRegisterValue(property->key()); 60061cb0ef41Sopenharmony_ci BuildPrivateBrandCheck(property, object); 60071cb0ef41Sopenharmony_ci BuildPrivateGetterAccess(object, key); 60081cb0ef41Sopenharmony_ci break; 60091cb0ef41Sopenharmony_ci } 60101cb0ef41Sopenharmony_ci } 60111cb0ef41Sopenharmony_ci 60121cb0ef41Sopenharmony_ci // Save result for postfix expressions. 60131cb0ef41Sopenharmony_ci FeedbackSlot count_slot = feedback_spec()->AddBinaryOpICSlot(); 60141cb0ef41Sopenharmony_ci if (is_postfix) { 60151cb0ef41Sopenharmony_ci old_value = register_allocator()->NewRegister(); 60161cb0ef41Sopenharmony_ci // Convert old value into a number before saving it. 60171cb0ef41Sopenharmony_ci // TODO(ignition): Think about adding proper PostInc/PostDec bytecodes 60181cb0ef41Sopenharmony_ci // instead of this ToNumeric + Inc/Dec dance. 60191cb0ef41Sopenharmony_ci builder() 60201cb0ef41Sopenharmony_ci ->ToNumeric(feedback_index(count_slot)) 60211cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(old_value); 60221cb0ef41Sopenharmony_ci } 60231cb0ef41Sopenharmony_ci 60241cb0ef41Sopenharmony_ci // Perform +1/-1 operation. 60251cb0ef41Sopenharmony_ci builder()->UnaryOperation(expr->op(), feedback_index(count_slot)); 60261cb0ef41Sopenharmony_ci 60271cb0ef41Sopenharmony_ci // Store the value. 60281cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 60291cb0ef41Sopenharmony_ci switch (assign_type) { 60301cb0ef41Sopenharmony_ci case NON_PROPERTY: { 60311cb0ef41Sopenharmony_ci VariableProxy* proxy = expr->expression()->AsVariableProxy(); 60321cb0ef41Sopenharmony_ci BuildVariableAssignment(proxy->var(), expr->op(), 60331cb0ef41Sopenharmony_ci proxy->hole_check_mode()); 60341cb0ef41Sopenharmony_ci break; 60351cb0ef41Sopenharmony_ci } 60361cb0ef41Sopenharmony_ci case NAMED_PROPERTY: { 60371cb0ef41Sopenharmony_ci FeedbackSlot slot = GetCachedStoreICSlot(property->obj(), name); 60381cb0ef41Sopenharmony_ci Register value; 60391cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 60401cb0ef41Sopenharmony_ci value = register_allocator()->NewRegister(); 60411cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(value); 60421cb0ef41Sopenharmony_ci } 60431cb0ef41Sopenharmony_ci builder()->SetNamedProperty(object, name, feedback_index(slot), 60441cb0ef41Sopenharmony_ci language_mode()); 60451cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 60461cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value); 60471cb0ef41Sopenharmony_ci } 60481cb0ef41Sopenharmony_ci break; 60491cb0ef41Sopenharmony_ci } 60501cb0ef41Sopenharmony_ci case KEYED_PROPERTY: { 60511cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode()); 60521cb0ef41Sopenharmony_ci Register value; 60531cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 60541cb0ef41Sopenharmony_ci value = register_allocator()->NewRegister(); 60551cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(value); 60561cb0ef41Sopenharmony_ci } 60571cb0ef41Sopenharmony_ci builder()->SetKeyedProperty(object, key, feedback_index(slot), 60581cb0ef41Sopenharmony_ci language_mode()); 60591cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 60601cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value); 60611cb0ef41Sopenharmony_ci } 60621cb0ef41Sopenharmony_ci break; 60631cb0ef41Sopenharmony_ci } 60641cb0ef41Sopenharmony_ci case NAMED_SUPER_PROPERTY: { 60651cb0ef41Sopenharmony_ci builder() 60661cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(super_property_args[3]) 60671cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kStoreToSuper, super_property_args); 60681cb0ef41Sopenharmony_ci break; 60691cb0ef41Sopenharmony_ci } 60701cb0ef41Sopenharmony_ci case KEYED_SUPER_PROPERTY: { 60711cb0ef41Sopenharmony_ci builder() 60721cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(super_property_args[3]) 60731cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kStoreKeyedToSuper, super_property_args); 60741cb0ef41Sopenharmony_ci break; 60751cb0ef41Sopenharmony_ci } 60761cb0ef41Sopenharmony_ci case PRIVATE_SETTER_ONLY: 60771cb0ef41Sopenharmony_ci case PRIVATE_GETTER_ONLY: 60781cb0ef41Sopenharmony_ci case PRIVATE_METHOD: { 60791cb0ef41Sopenharmony_ci UNREACHABLE(); 60801cb0ef41Sopenharmony_ci } 60811cb0ef41Sopenharmony_ci case PRIVATE_GETTER_AND_SETTER: { 60821cb0ef41Sopenharmony_ci Register value = register_allocator()->NewRegister(); 60831cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(value); 60841cb0ef41Sopenharmony_ci BuildPrivateSetterAccess(object, key, value); 60851cb0ef41Sopenharmony_ci if (!execution_result()->IsEffect()) { 60861cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(value); 60871cb0ef41Sopenharmony_ci } 60881cb0ef41Sopenharmony_ci break; 60891cb0ef41Sopenharmony_ci } 60901cb0ef41Sopenharmony_ci } 60911cb0ef41Sopenharmony_ci 60921cb0ef41Sopenharmony_ci // Restore old value for postfix expressions. 60931cb0ef41Sopenharmony_ci if (is_postfix) { 60941cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(old_value); 60951cb0ef41Sopenharmony_ci } 60961cb0ef41Sopenharmony_ci} 60971cb0ef41Sopenharmony_ci 60981cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) { 60991cb0ef41Sopenharmony_ci switch (binop->op()) { 61001cb0ef41Sopenharmony_ci case Token::COMMA: 61011cb0ef41Sopenharmony_ci VisitCommaExpression(binop); 61021cb0ef41Sopenharmony_ci break; 61031cb0ef41Sopenharmony_ci case Token::OR: 61041cb0ef41Sopenharmony_ci VisitLogicalOrExpression(binop); 61051cb0ef41Sopenharmony_ci break; 61061cb0ef41Sopenharmony_ci case Token::AND: 61071cb0ef41Sopenharmony_ci VisitLogicalAndExpression(binop); 61081cb0ef41Sopenharmony_ci break; 61091cb0ef41Sopenharmony_ci case Token::NULLISH: 61101cb0ef41Sopenharmony_ci VisitNullishExpression(binop); 61111cb0ef41Sopenharmony_ci break; 61121cb0ef41Sopenharmony_ci default: 61131cb0ef41Sopenharmony_ci VisitArithmeticExpression(binop); 61141cb0ef41Sopenharmony_ci break; 61151cb0ef41Sopenharmony_ci } 61161cb0ef41Sopenharmony_ci} 61171cb0ef41Sopenharmony_ci 61181cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNaryOperation(NaryOperation* expr) { 61191cb0ef41Sopenharmony_ci switch (expr->op()) { 61201cb0ef41Sopenharmony_ci case Token::COMMA: 61211cb0ef41Sopenharmony_ci VisitNaryCommaExpression(expr); 61221cb0ef41Sopenharmony_ci break; 61231cb0ef41Sopenharmony_ci case Token::OR: 61241cb0ef41Sopenharmony_ci VisitNaryLogicalOrExpression(expr); 61251cb0ef41Sopenharmony_ci break; 61261cb0ef41Sopenharmony_ci case Token::AND: 61271cb0ef41Sopenharmony_ci VisitNaryLogicalAndExpression(expr); 61281cb0ef41Sopenharmony_ci break; 61291cb0ef41Sopenharmony_ci case Token::NULLISH: 61301cb0ef41Sopenharmony_ci VisitNaryNullishExpression(expr); 61311cb0ef41Sopenharmony_ci break; 61321cb0ef41Sopenharmony_ci default: 61331cb0ef41Sopenharmony_ci VisitNaryArithmeticExpression(expr); 61341cb0ef41Sopenharmony_ci break; 61351cb0ef41Sopenharmony_ci } 61361cb0ef41Sopenharmony_ci} 61371cb0ef41Sopenharmony_ci 61381cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildLiteralCompareNil( 61391cb0ef41Sopenharmony_ci Token::Value op, BytecodeArrayBuilder::NilValue nil) { 61401cb0ef41Sopenharmony_ci if (execution_result()->IsTest()) { 61411cb0ef41Sopenharmony_ci TestResultScope* test_result = execution_result()->AsTest(); 61421cb0ef41Sopenharmony_ci switch (test_result->fallthrough()) { 61431cb0ef41Sopenharmony_ci case TestFallthrough::kThen: 61441cb0ef41Sopenharmony_ci builder()->JumpIfNotNil(test_result->NewElseLabel(), op, nil); 61451cb0ef41Sopenharmony_ci break; 61461cb0ef41Sopenharmony_ci case TestFallthrough::kElse: 61471cb0ef41Sopenharmony_ci builder()->JumpIfNil(test_result->NewThenLabel(), op, nil); 61481cb0ef41Sopenharmony_ci break; 61491cb0ef41Sopenharmony_ci case TestFallthrough::kNone: 61501cb0ef41Sopenharmony_ci builder() 61511cb0ef41Sopenharmony_ci ->JumpIfNil(test_result->NewThenLabel(), op, nil) 61521cb0ef41Sopenharmony_ci .Jump(test_result->NewElseLabel()); 61531cb0ef41Sopenharmony_ci } 61541cb0ef41Sopenharmony_ci test_result->SetResultConsumedByTest(); 61551cb0ef41Sopenharmony_ci } else { 61561cb0ef41Sopenharmony_ci builder()->CompareNil(op, nil); 61571cb0ef41Sopenharmony_ci } 61581cb0ef41Sopenharmony_ci} 61591cb0ef41Sopenharmony_ci 61601cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { 61611cb0ef41Sopenharmony_ci Expression* sub_expr; 61621cb0ef41Sopenharmony_ci Literal* literal; 61631cb0ef41Sopenharmony_ci if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) { 61641cb0ef41Sopenharmony_ci // Emit a fast literal comparion for expressions of the form: 61651cb0ef41Sopenharmony_ci // typeof(x) === 'string'. 61661cb0ef41Sopenharmony_ci VisitForTypeOfValue(sub_expr); 61671cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 61681cb0ef41Sopenharmony_ci TestTypeOfFlags::LiteralFlag literal_flag = 61691cb0ef41Sopenharmony_ci TestTypeOfFlags::GetFlagForLiteral(ast_string_constants(), literal); 61701cb0ef41Sopenharmony_ci if (literal_flag == TestTypeOfFlags::LiteralFlag::kOther) { 61711cb0ef41Sopenharmony_ci builder()->LoadFalse(); 61721cb0ef41Sopenharmony_ci } else { 61731cb0ef41Sopenharmony_ci builder()->CompareTypeOf(literal_flag); 61741cb0ef41Sopenharmony_ci } 61751cb0ef41Sopenharmony_ci } else if (expr->IsLiteralCompareUndefined(&sub_expr)) { 61761cb0ef41Sopenharmony_ci VisitForAccumulatorValue(sub_expr); 61771cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 61781cb0ef41Sopenharmony_ci BuildLiteralCompareNil(expr->op(), BytecodeArrayBuilder::kUndefinedValue); 61791cb0ef41Sopenharmony_ci } else if (expr->IsLiteralCompareNull(&sub_expr)) { 61801cb0ef41Sopenharmony_ci VisitForAccumulatorValue(sub_expr); 61811cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 61821cb0ef41Sopenharmony_ci BuildLiteralCompareNil(expr->op(), BytecodeArrayBuilder::kNullValue); 61831cb0ef41Sopenharmony_ci } else { 61841cb0ef41Sopenharmony_ci if (expr->op() == Token::IN && expr->left()->IsPrivateName()) { 61851cb0ef41Sopenharmony_ci DCHECK(FLAG_harmony_private_brand_checks); 61861cb0ef41Sopenharmony_ci Variable* var = expr->left()->AsVariableProxy()->var(); 61871cb0ef41Sopenharmony_ci if (IsPrivateMethodOrAccessorVariableMode(var->mode())) { 61881cb0ef41Sopenharmony_ci BuildPrivateMethodIn(var, expr->right()); 61891cb0ef41Sopenharmony_ci return; 61901cb0ef41Sopenharmony_ci } 61911cb0ef41Sopenharmony_ci // For private fields, the code below does the right thing. 61921cb0ef41Sopenharmony_ci } 61931cb0ef41Sopenharmony_ci 61941cb0ef41Sopenharmony_ci Register lhs = VisitForRegisterValue(expr->left()); 61951cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->right()); 61961cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 61971cb0ef41Sopenharmony_ci FeedbackSlot slot; 61981cb0ef41Sopenharmony_ci if (expr->op() == Token::IN) { 61991cb0ef41Sopenharmony_ci slot = feedback_spec()->AddKeyedHasICSlot(); 62001cb0ef41Sopenharmony_ci } else if (expr->op() == Token::INSTANCEOF) { 62011cb0ef41Sopenharmony_ci slot = feedback_spec()->AddInstanceOfSlot(); 62021cb0ef41Sopenharmony_ci } else { 62031cb0ef41Sopenharmony_ci slot = feedback_spec()->AddCompareICSlot(); 62041cb0ef41Sopenharmony_ci } 62051cb0ef41Sopenharmony_ci builder()->CompareOperation(expr->op(), lhs, feedback_index(slot)); 62061cb0ef41Sopenharmony_ci } 62071cb0ef41Sopenharmony_ci // Always returns a boolean value. 62081cb0ef41Sopenharmony_ci execution_result()->SetResultIsBoolean(); 62091cb0ef41Sopenharmony_ci} 62101cb0ef41Sopenharmony_ci 62111cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { 62121cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot(); 62131cb0ef41Sopenharmony_ci Expression* subexpr; 62141cb0ef41Sopenharmony_ci Smi literal; 62151cb0ef41Sopenharmony_ci if (expr->IsSmiLiteralOperation(&subexpr, &literal)) { 62161cb0ef41Sopenharmony_ci TypeHint type_hint = VisitForAccumulatorValue(subexpr); 62171cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 62181cb0ef41Sopenharmony_ci builder()->BinaryOperationSmiLiteral(expr->op(), literal, 62191cb0ef41Sopenharmony_ci feedback_index(slot)); 62201cb0ef41Sopenharmony_ci if (expr->op() == Token::ADD && type_hint == TypeHint::kString) { 62211cb0ef41Sopenharmony_ci execution_result()->SetResultIsString(); 62221cb0ef41Sopenharmony_ci } 62231cb0ef41Sopenharmony_ci } else { 62241cb0ef41Sopenharmony_ci TypeHint lhs_type = VisitForAccumulatorValue(expr->left()); 62251cb0ef41Sopenharmony_ci Register lhs = register_allocator()->NewRegister(); 62261cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(lhs); 62271cb0ef41Sopenharmony_ci TypeHint rhs_type = VisitForAccumulatorValue(expr->right()); 62281cb0ef41Sopenharmony_ci if (expr->op() == Token::ADD && 62291cb0ef41Sopenharmony_ci (lhs_type == TypeHint::kString || rhs_type == TypeHint::kString)) { 62301cb0ef41Sopenharmony_ci execution_result()->SetResultIsString(); 62311cb0ef41Sopenharmony_ci } 62321cb0ef41Sopenharmony_ci 62331cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 62341cb0ef41Sopenharmony_ci builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); 62351cb0ef41Sopenharmony_ci } 62361cb0ef41Sopenharmony_ci} 62371cb0ef41Sopenharmony_ci 62381cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNaryArithmeticExpression(NaryOperation* expr) { 62391cb0ef41Sopenharmony_ci // TODO(leszeks): Add support for lhs smi in commutative ops. 62401cb0ef41Sopenharmony_ci TypeHint type_hint = VisitForAccumulatorValue(expr->first()); 62411cb0ef41Sopenharmony_ci 62421cb0ef41Sopenharmony_ci for (size_t i = 0; i < expr->subsequent_length(); ++i) { 62431cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 62441cb0ef41Sopenharmony_ci if (expr->subsequent(i)->IsSmiLiteral()) { 62451cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr->subsequent_op_position(i)); 62461cb0ef41Sopenharmony_ci builder()->BinaryOperationSmiLiteral( 62471cb0ef41Sopenharmony_ci expr->op(), expr->subsequent(i)->AsLiteral()->AsSmiLiteral(), 62481cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddBinaryOpICSlot())); 62491cb0ef41Sopenharmony_ci } else { 62501cb0ef41Sopenharmony_ci Register lhs = register_allocator()->NewRegister(); 62511cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(lhs); 62521cb0ef41Sopenharmony_ci TypeHint rhs_hint = VisitForAccumulatorValue(expr->subsequent(i)); 62531cb0ef41Sopenharmony_ci if (rhs_hint == TypeHint::kString) type_hint = TypeHint::kString; 62541cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr->subsequent_op_position(i)); 62551cb0ef41Sopenharmony_ci builder()->BinaryOperation( 62561cb0ef41Sopenharmony_ci expr->op(), lhs, 62571cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddBinaryOpICSlot())); 62581cb0ef41Sopenharmony_ci } 62591cb0ef41Sopenharmony_ci } 62601cb0ef41Sopenharmony_ci 62611cb0ef41Sopenharmony_ci if (type_hint == TypeHint::kString && expr->op() == Token::ADD) { 62621cb0ef41Sopenharmony_ci // If any operand of an ADD is a String, a String is produced. 62631cb0ef41Sopenharmony_ci execution_result()->SetResultIsString(); 62641cb0ef41Sopenharmony_ci } 62651cb0ef41Sopenharmony_ci} 62661cb0ef41Sopenharmony_ci 62671cb0ef41Sopenharmony_ci// Note: the actual spreading is performed by the surrounding expression's 62681cb0ef41Sopenharmony_ci// visitor. 62691cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); } 62701cb0ef41Sopenharmony_ci 62711cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { 62721cb0ef41Sopenharmony_ci UNREACHABLE(); 62731cb0ef41Sopenharmony_ci} 62741cb0ef41Sopenharmony_ci 62751cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitImportCallExpression(ImportCallExpression* expr) { 62761cb0ef41Sopenharmony_ci const int register_count = expr->import_assertions() ? 3 : 2; 62771cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(register_count); 62781cb0ef41Sopenharmony_ci VisitForRegisterValue(expr->specifier(), args[1]); 62791cb0ef41Sopenharmony_ci if (expr->import_assertions()) { 62801cb0ef41Sopenharmony_ci VisitForRegisterValue(expr->import_assertions(), args[2]); 62811cb0ef41Sopenharmony_ci } 62821cb0ef41Sopenharmony_ci builder() 62831cb0ef41Sopenharmony_ci ->MoveRegister(Register::function_closure(), args[0]) 62841cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kDynamicImportCall, args); 62851cb0ef41Sopenharmony_ci} 62861cb0ef41Sopenharmony_ci 62871cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildGetIterator(IteratorType hint) { 62881cb0ef41Sopenharmony_ci if (hint == IteratorType::kAsync) { 62891cb0ef41Sopenharmony_ci RegisterAllocationScope scope(this); 62901cb0ef41Sopenharmony_ci 62911cb0ef41Sopenharmony_ci Register obj = register_allocator()->NewRegister(); 62921cb0ef41Sopenharmony_ci Register method = register_allocator()->NewRegister(); 62931cb0ef41Sopenharmony_ci 62941cb0ef41Sopenharmony_ci // Set method to GetMethod(obj, @@asyncIterator) 62951cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(obj).LoadAsyncIteratorProperty( 62961cb0ef41Sopenharmony_ci obj, feedback_index(feedback_spec()->AddLoadICSlot())); 62971cb0ef41Sopenharmony_ci 62981cb0ef41Sopenharmony_ci BytecodeLabel async_iterator_undefined, done; 62991cb0ef41Sopenharmony_ci builder()->JumpIfUndefinedOrNull(&async_iterator_undefined); 63001cb0ef41Sopenharmony_ci 63011cb0ef41Sopenharmony_ci // Let iterator be Call(method, obj) 63021cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(method).CallProperty( 63031cb0ef41Sopenharmony_ci method, RegisterList(obj), 63041cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot())); 63051cb0ef41Sopenharmony_ci 63061cb0ef41Sopenharmony_ci // If Type(iterator) is not Object, throw a TypeError exception. 63071cb0ef41Sopenharmony_ci builder()->JumpIfJSReceiver(&done); 63081cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kThrowSymbolAsyncIteratorInvalid); 63091cb0ef41Sopenharmony_ci 63101cb0ef41Sopenharmony_ci builder()->Bind(&async_iterator_undefined); 63111cb0ef41Sopenharmony_ci // If method is undefined, 63121cb0ef41Sopenharmony_ci // Let syncMethod be GetMethod(obj, @@iterator) 63131cb0ef41Sopenharmony_ci builder() 63141cb0ef41Sopenharmony_ci ->LoadIteratorProperty(obj, 63151cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLoadICSlot())) 63161cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(method); 63171cb0ef41Sopenharmony_ci 63181cb0ef41Sopenharmony_ci // Let syncIterator be Call(syncMethod, obj) 63191cb0ef41Sopenharmony_ci builder()->CallProperty(method, RegisterList(obj), 63201cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot())); 63211cb0ef41Sopenharmony_ci 63221cb0ef41Sopenharmony_ci // Return CreateAsyncFromSyncIterator(syncIterator) 63231cb0ef41Sopenharmony_ci // alias `method` register as it's no longer used 63241cb0ef41Sopenharmony_ci Register sync_iter = method; 63251cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(sync_iter).CallRuntime( 63261cb0ef41Sopenharmony_ci Runtime::kInlineCreateAsyncFromSyncIterator, sync_iter); 63271cb0ef41Sopenharmony_ci 63281cb0ef41Sopenharmony_ci builder()->Bind(&done); 63291cb0ef41Sopenharmony_ci } else { 63301cb0ef41Sopenharmony_ci { 63311cb0ef41Sopenharmony_ci RegisterAllocationScope scope(this); 63321cb0ef41Sopenharmony_ci 63331cb0ef41Sopenharmony_ci Register obj = register_allocator()->NewRegister(); 63341cb0ef41Sopenharmony_ci int load_feedback_index = 63351cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLoadICSlot()); 63361cb0ef41Sopenharmony_ci int call_feedback_index = 63371cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot()); 63381cb0ef41Sopenharmony_ci 63391cb0ef41Sopenharmony_ci // Let method be GetMethod(obj, @@iterator) and 63401cb0ef41Sopenharmony_ci // iterator be Call(method, obj). 63411cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(obj).GetIterator( 63421cb0ef41Sopenharmony_ci obj, load_feedback_index, call_feedback_index); 63431cb0ef41Sopenharmony_ci } 63441cb0ef41Sopenharmony_ci 63451cb0ef41Sopenharmony_ci // If Type(iterator) is not Object, throw a TypeError exception. 63461cb0ef41Sopenharmony_ci BytecodeLabel no_type_error; 63471cb0ef41Sopenharmony_ci builder()->JumpIfJSReceiver(&no_type_error); 63481cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid); 63491cb0ef41Sopenharmony_ci builder()->Bind(&no_type_error); 63501cb0ef41Sopenharmony_ci } 63511cb0ef41Sopenharmony_ci} 63521cb0ef41Sopenharmony_ci 63531cb0ef41Sopenharmony_ci// Returns an IteratorRecord which is valid for the lifetime of the current 63541cb0ef41Sopenharmony_ci// register_allocation_scope. 63551cb0ef41Sopenharmony_ciBytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord( 63561cb0ef41Sopenharmony_ci Register next, Register object, IteratorType hint) { 63571cb0ef41Sopenharmony_ci DCHECK(next.is_valid() && object.is_valid()); 63581cb0ef41Sopenharmony_ci BuildGetIterator(hint); 63591cb0ef41Sopenharmony_ci 63601cb0ef41Sopenharmony_ci builder() 63611cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(object) 63621cb0ef41Sopenharmony_ci .LoadNamedProperty(object, ast_string_constants()->next_string(), 63631cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddLoadICSlot())) 63641cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(next); 63651cb0ef41Sopenharmony_ci return IteratorRecord(object, next, hint); 63661cb0ef41Sopenharmony_ci} 63671cb0ef41Sopenharmony_ci 63681cb0ef41Sopenharmony_ciBytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord( 63691cb0ef41Sopenharmony_ci IteratorType hint) { 63701cb0ef41Sopenharmony_ci Register next = register_allocator()->NewRegister(); 63711cb0ef41Sopenharmony_ci Register object = register_allocator()->NewRegister(); 63721cb0ef41Sopenharmony_ci return BuildGetIteratorRecord(next, object, hint); 63731cb0ef41Sopenharmony_ci} 63741cb0ef41Sopenharmony_ci 63751cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildIteratorNext(const IteratorRecord& iterator, 63761cb0ef41Sopenharmony_ci Register next_result) { 63771cb0ef41Sopenharmony_ci DCHECK(next_result.is_valid()); 63781cb0ef41Sopenharmony_ci builder()->CallProperty(iterator.next(), RegisterList(iterator.object()), 63791cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot())); 63801cb0ef41Sopenharmony_ci 63811cb0ef41Sopenharmony_ci if (iterator.type() == IteratorType::kAsync) { 63821cb0ef41Sopenharmony_ci BuildAwait(); 63831cb0ef41Sopenharmony_ci } 63841cb0ef41Sopenharmony_ci 63851cb0ef41Sopenharmony_ci BytecodeLabel is_object; 63861cb0ef41Sopenharmony_ci builder() 63871cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(next_result) 63881cb0ef41Sopenharmony_ci .JumpIfJSReceiver(&is_object) 63891cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, next_result) 63901cb0ef41Sopenharmony_ci .Bind(&is_object); 63911cb0ef41Sopenharmony_ci} 63921cb0ef41Sopenharmony_ci 63931cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildCallIteratorMethod(Register iterator, 63941cb0ef41Sopenharmony_ci const AstRawString* method_name, 63951cb0ef41Sopenharmony_ci RegisterList receiver_and_args, 63961cb0ef41Sopenharmony_ci BytecodeLabel* if_called, 63971cb0ef41Sopenharmony_ci BytecodeLabels* if_notcalled) { 63981cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 63991cb0ef41Sopenharmony_ci 64001cb0ef41Sopenharmony_ci Register method = register_allocator()->NewRegister(); 64011cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddLoadICSlot(); 64021cb0ef41Sopenharmony_ci builder() 64031cb0ef41Sopenharmony_ci ->LoadNamedProperty(iterator, method_name, feedback_index(slot)) 64041cb0ef41Sopenharmony_ci .JumpIfUndefinedOrNull(if_notcalled->New()) 64051cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(method) 64061cb0ef41Sopenharmony_ci .CallProperty(method, receiver_and_args, 64071cb0ef41Sopenharmony_ci feedback_index(feedback_spec()->AddCallICSlot())) 64081cb0ef41Sopenharmony_ci .Jump(if_called); 64091cb0ef41Sopenharmony_ci} 64101cb0ef41Sopenharmony_ci 64111cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildIteratorClose(const IteratorRecord& iterator, 64121cb0ef41Sopenharmony_ci Expression* expr) { 64131cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 64141cb0ef41Sopenharmony_ci BytecodeLabels done(zone()); 64151cb0ef41Sopenharmony_ci BytecodeLabel if_called; 64161cb0ef41Sopenharmony_ci RegisterList args = RegisterList(iterator.object()); 64171cb0ef41Sopenharmony_ci BuildCallIteratorMethod(iterator.object(), 64181cb0ef41Sopenharmony_ci ast_string_constants()->return_string(), args, 64191cb0ef41Sopenharmony_ci &if_called, &done); 64201cb0ef41Sopenharmony_ci builder()->Bind(&if_called); 64211cb0ef41Sopenharmony_ci 64221cb0ef41Sopenharmony_ci if (iterator.type() == IteratorType::kAsync) { 64231cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(expr); 64241cb0ef41Sopenharmony_ci BuildAwait(expr->position()); 64251cb0ef41Sopenharmony_ci } 64261cb0ef41Sopenharmony_ci 64271cb0ef41Sopenharmony_ci builder()->JumpIfJSReceiver(done.New()); 64281cb0ef41Sopenharmony_ci { 64291cb0ef41Sopenharmony_ci RegisterAllocationScope inner_register_scope(this); 64301cb0ef41Sopenharmony_ci Register return_result = register_allocator()->NewRegister(); 64311cb0ef41Sopenharmony_ci builder() 64321cb0ef41Sopenharmony_ci ->StoreAccumulatorInRegister(return_result) 64331cb0ef41Sopenharmony_ci .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, return_result); 64341cb0ef41Sopenharmony_ci } 64351cb0ef41Sopenharmony_ci 64361cb0ef41Sopenharmony_ci done.Bind(builder()); 64371cb0ef41Sopenharmony_ci} 64381cb0ef41Sopenharmony_ci 64391cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitGetTemplateObject(GetTemplateObject* expr) { 64401cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 64411cb0ef41Sopenharmony_ci size_t entry = builder()->AllocateDeferredConstantPoolEntry(); 64421cb0ef41Sopenharmony_ci template_objects_.push_back(std::make_pair(expr, entry)); 64431cb0ef41Sopenharmony_ci FeedbackSlot literal_slot = feedback_spec()->AddLiteralSlot(); 64441cb0ef41Sopenharmony_ci builder()->GetTemplateObject(entry, feedback_index(literal_slot)); 64451cb0ef41Sopenharmony_ci} 64461cb0ef41Sopenharmony_ci 64471cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitTemplateLiteral(TemplateLiteral* expr) { 64481cb0ef41Sopenharmony_ci const ZonePtrList<const AstRawString>& parts = *expr->string_parts(); 64491cb0ef41Sopenharmony_ci const ZonePtrList<Expression>& substitutions = *expr->substitutions(); 64501cb0ef41Sopenharmony_ci // Template strings with no substitutions are turned into StringLiterals. 64511cb0ef41Sopenharmony_ci DCHECK_GT(substitutions.length(), 0); 64521cb0ef41Sopenharmony_ci DCHECK_EQ(parts.length(), substitutions.length() + 1); 64531cb0ef41Sopenharmony_ci 64541cb0ef41Sopenharmony_ci // Generate string concatenation 64551cb0ef41Sopenharmony_ci // TODO(caitp): Don't generate feedback slot if it's not used --- introduce 64561cb0ef41Sopenharmony_ci // a simple, concise, reusable mechanism to lazily create reusable slots. 64571cb0ef41Sopenharmony_ci FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot(); 64581cb0ef41Sopenharmony_ci Register last_part = register_allocator()->NewRegister(); 64591cb0ef41Sopenharmony_ci bool last_part_valid = false; 64601cb0ef41Sopenharmony_ci 64611cb0ef41Sopenharmony_ci builder()->SetExpressionPosition(expr); 64621cb0ef41Sopenharmony_ci for (int i = 0; i < substitutions.length(); ++i) { 64631cb0ef41Sopenharmony_ci if (i != 0) { 64641cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(last_part); 64651cb0ef41Sopenharmony_ci last_part_valid = true; 64661cb0ef41Sopenharmony_ci } 64671cb0ef41Sopenharmony_ci 64681cb0ef41Sopenharmony_ci if (!parts[i]->IsEmpty()) { 64691cb0ef41Sopenharmony_ci builder()->LoadLiteral(parts[i]); 64701cb0ef41Sopenharmony_ci if (last_part_valid) { 64711cb0ef41Sopenharmony_ci builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot)); 64721cb0ef41Sopenharmony_ci } 64731cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(last_part); 64741cb0ef41Sopenharmony_ci last_part_valid = true; 64751cb0ef41Sopenharmony_ci } 64761cb0ef41Sopenharmony_ci 64771cb0ef41Sopenharmony_ci TypeHint type_hint = VisitForAccumulatorValue(substitutions[i]); 64781cb0ef41Sopenharmony_ci if (type_hint != TypeHint::kString) { 64791cb0ef41Sopenharmony_ci builder()->ToString(); 64801cb0ef41Sopenharmony_ci } 64811cb0ef41Sopenharmony_ci if (last_part_valid) { 64821cb0ef41Sopenharmony_ci builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot)); 64831cb0ef41Sopenharmony_ci } 64841cb0ef41Sopenharmony_ci last_part_valid = false; 64851cb0ef41Sopenharmony_ci } 64861cb0ef41Sopenharmony_ci 64871cb0ef41Sopenharmony_ci if (!parts.last()->IsEmpty()) { 64881cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(last_part); 64891cb0ef41Sopenharmony_ci builder()->LoadLiteral(parts.last()); 64901cb0ef41Sopenharmony_ci builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot)); 64911cb0ef41Sopenharmony_ci } 64921cb0ef41Sopenharmony_ci} 64931cb0ef41Sopenharmony_ci 64941cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildThisVariableLoad() { 64951cb0ef41Sopenharmony_ci DeclarationScope* receiver_scope = closure_scope()->GetReceiverScope(); 64961cb0ef41Sopenharmony_ci Variable* var = receiver_scope->receiver(); 64971cb0ef41Sopenharmony_ci // TODO(littledan): implement 'this' hole check elimination. 64981cb0ef41Sopenharmony_ci HoleCheckMode hole_check_mode = 64991cb0ef41Sopenharmony_ci IsDerivedConstructor(receiver_scope->function_kind()) 65001cb0ef41Sopenharmony_ci ? HoleCheckMode::kRequired 65011cb0ef41Sopenharmony_ci : HoleCheckMode::kElided; 65021cb0ef41Sopenharmony_ci BuildVariableLoad(var, hole_check_mode); 65031cb0ef41Sopenharmony_ci} 65041cb0ef41Sopenharmony_ci 65051cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitThisExpression(ThisExpression* expr) { 65061cb0ef41Sopenharmony_ci BuildThisVariableLoad(); 65071cb0ef41Sopenharmony_ci} 65081cb0ef41Sopenharmony_ci 65091cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) { 65101cb0ef41Sopenharmony_ci // Handled by VisitCall(). 65111cb0ef41Sopenharmony_ci UNREACHABLE(); 65121cb0ef41Sopenharmony_ci} 65131cb0ef41Sopenharmony_ci 65141cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitSuperPropertyReference( 65151cb0ef41Sopenharmony_ci SuperPropertyReference* expr) { 65161cb0ef41Sopenharmony_ci builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError); 65171cb0ef41Sopenharmony_ci} 65181cb0ef41Sopenharmony_ci 65191cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { 65201cb0ef41Sopenharmony_ci VisitForEffect(binop->left()); 65211cb0ef41Sopenharmony_ci Visit(binop->right()); 65221cb0ef41Sopenharmony_ci} 65231cb0ef41Sopenharmony_ci 65241cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNaryCommaExpression(NaryOperation* expr) { 65251cb0ef41Sopenharmony_ci DCHECK_GT(expr->subsequent_length(), 0); 65261cb0ef41Sopenharmony_ci 65271cb0ef41Sopenharmony_ci VisitForEffect(expr->first()); 65281cb0ef41Sopenharmony_ci for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) { 65291cb0ef41Sopenharmony_ci VisitForEffect(expr->subsequent(i)); 65301cb0ef41Sopenharmony_ci } 65311cb0ef41Sopenharmony_ci Visit(expr->subsequent(expr->subsequent_length() - 1)); 65321cb0ef41Sopenharmony_ci} 65331cb0ef41Sopenharmony_ci 65341cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitLogicalTestSubExpression( 65351cb0ef41Sopenharmony_ci Token::Value token, Expression* expr, BytecodeLabels* then_labels, 65361cb0ef41Sopenharmony_ci BytecodeLabels* else_labels, int coverage_slot) { 65371cb0ef41Sopenharmony_ci DCHECK(token == Token::OR || token == Token::AND || token == Token::NULLISH); 65381cb0ef41Sopenharmony_ci 65391cb0ef41Sopenharmony_ci BytecodeLabels test_next(zone()); 65401cb0ef41Sopenharmony_ci if (token == Token::OR) { 65411cb0ef41Sopenharmony_ci VisitForTest(expr, then_labels, &test_next, TestFallthrough::kElse); 65421cb0ef41Sopenharmony_ci } else if (token == Token::AND) { 65431cb0ef41Sopenharmony_ci VisitForTest(expr, &test_next, else_labels, TestFallthrough::kThen); 65441cb0ef41Sopenharmony_ci } else { 65451cb0ef41Sopenharmony_ci DCHECK_EQ(Token::NULLISH, token); 65461cb0ef41Sopenharmony_ci VisitForNullishTest(expr, then_labels, &test_next, else_labels); 65471cb0ef41Sopenharmony_ci } 65481cb0ef41Sopenharmony_ci test_next.Bind(builder()); 65491cb0ef41Sopenharmony_ci 65501cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot); 65511cb0ef41Sopenharmony_ci} 65521cb0ef41Sopenharmony_ci 65531cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitLogicalTest(Token::Value token, Expression* left, 65541cb0ef41Sopenharmony_ci Expression* right, 65551cb0ef41Sopenharmony_ci int right_coverage_slot) { 65561cb0ef41Sopenharmony_ci DCHECK(token == Token::OR || token == Token::AND || token == Token::NULLISH); 65571cb0ef41Sopenharmony_ci TestResultScope* test_result = execution_result()->AsTest(); 65581cb0ef41Sopenharmony_ci BytecodeLabels* then_labels = test_result->then_labels(); 65591cb0ef41Sopenharmony_ci BytecodeLabels* else_labels = test_result->else_labels(); 65601cb0ef41Sopenharmony_ci TestFallthrough fallthrough = test_result->fallthrough(); 65611cb0ef41Sopenharmony_ci 65621cb0ef41Sopenharmony_ci VisitLogicalTestSubExpression(token, left, then_labels, else_labels, 65631cb0ef41Sopenharmony_ci right_coverage_slot); 65641cb0ef41Sopenharmony_ci // The last test has the same then, else and fallthrough as the parent test. 65651cb0ef41Sopenharmony_ci VisitForTest(right, then_labels, else_labels, fallthrough); 65661cb0ef41Sopenharmony_ci} 65671cb0ef41Sopenharmony_ci 65681cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNaryLogicalTest( 65691cb0ef41Sopenharmony_ci Token::Value token, NaryOperation* expr, 65701cb0ef41Sopenharmony_ci const NaryCodeCoverageSlots* coverage_slots) { 65711cb0ef41Sopenharmony_ci DCHECK(token == Token::OR || token == Token::AND || token == Token::NULLISH); 65721cb0ef41Sopenharmony_ci DCHECK_GT(expr->subsequent_length(), 0); 65731cb0ef41Sopenharmony_ci 65741cb0ef41Sopenharmony_ci TestResultScope* test_result = execution_result()->AsTest(); 65751cb0ef41Sopenharmony_ci BytecodeLabels* then_labels = test_result->then_labels(); 65761cb0ef41Sopenharmony_ci BytecodeLabels* else_labels = test_result->else_labels(); 65771cb0ef41Sopenharmony_ci TestFallthrough fallthrough = test_result->fallthrough(); 65781cb0ef41Sopenharmony_ci 65791cb0ef41Sopenharmony_ci VisitLogicalTestSubExpression(token, expr->first(), then_labels, else_labels, 65801cb0ef41Sopenharmony_ci coverage_slots->GetSlotFor(0)); 65811cb0ef41Sopenharmony_ci for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) { 65821cb0ef41Sopenharmony_ci VisitLogicalTestSubExpression(token, expr->subsequent(i), then_labels, 65831cb0ef41Sopenharmony_ci else_labels, 65841cb0ef41Sopenharmony_ci coverage_slots->GetSlotFor(i + 1)); 65851cb0ef41Sopenharmony_ci } 65861cb0ef41Sopenharmony_ci // The last test has the same then, else and fallthrough as the parent test. 65871cb0ef41Sopenharmony_ci VisitForTest(expr->subsequent(expr->subsequent_length() - 1), then_labels, 65881cb0ef41Sopenharmony_ci else_labels, fallthrough); 65891cb0ef41Sopenharmony_ci} 65901cb0ef41Sopenharmony_ci 65911cb0ef41Sopenharmony_cibool BytecodeGenerator::VisitLogicalOrSubExpression(Expression* expr, 65921cb0ef41Sopenharmony_ci BytecodeLabels* end_labels, 65931cb0ef41Sopenharmony_ci int coverage_slot) { 65941cb0ef41Sopenharmony_ci if (expr->ToBooleanIsTrue()) { 65951cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr); 65961cb0ef41Sopenharmony_ci end_labels->Bind(builder()); 65971cb0ef41Sopenharmony_ci return true; 65981cb0ef41Sopenharmony_ci } else if (!expr->ToBooleanIsFalse()) { 65991cb0ef41Sopenharmony_ci TypeHint type_hint = VisitForAccumulatorValue(expr); 66001cb0ef41Sopenharmony_ci builder()->JumpIfTrue(ToBooleanModeFromTypeHint(type_hint), 66011cb0ef41Sopenharmony_ci end_labels->New()); 66021cb0ef41Sopenharmony_ci } 66031cb0ef41Sopenharmony_ci 66041cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot); 66051cb0ef41Sopenharmony_ci 66061cb0ef41Sopenharmony_ci return false; 66071cb0ef41Sopenharmony_ci} 66081cb0ef41Sopenharmony_ci 66091cb0ef41Sopenharmony_cibool BytecodeGenerator::VisitLogicalAndSubExpression(Expression* expr, 66101cb0ef41Sopenharmony_ci BytecodeLabels* end_labels, 66111cb0ef41Sopenharmony_ci int coverage_slot) { 66121cb0ef41Sopenharmony_ci if (expr->ToBooleanIsFalse()) { 66131cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr); 66141cb0ef41Sopenharmony_ci end_labels->Bind(builder()); 66151cb0ef41Sopenharmony_ci return true; 66161cb0ef41Sopenharmony_ci } else if (!expr->ToBooleanIsTrue()) { 66171cb0ef41Sopenharmony_ci TypeHint type_hint = VisitForAccumulatorValue(expr); 66181cb0ef41Sopenharmony_ci builder()->JumpIfFalse(ToBooleanModeFromTypeHint(type_hint), 66191cb0ef41Sopenharmony_ci end_labels->New()); 66201cb0ef41Sopenharmony_ci } 66211cb0ef41Sopenharmony_ci 66221cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot); 66231cb0ef41Sopenharmony_ci 66241cb0ef41Sopenharmony_ci return false; 66251cb0ef41Sopenharmony_ci} 66261cb0ef41Sopenharmony_ci 66271cb0ef41Sopenharmony_cibool BytecodeGenerator::VisitNullishSubExpression(Expression* expr, 66281cb0ef41Sopenharmony_ci BytecodeLabels* end_labels, 66291cb0ef41Sopenharmony_ci int coverage_slot) { 66301cb0ef41Sopenharmony_ci if (expr->IsLiteralButNotNullOrUndefined()) { 66311cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr); 66321cb0ef41Sopenharmony_ci end_labels->Bind(builder()); 66331cb0ef41Sopenharmony_ci return true; 66341cb0ef41Sopenharmony_ci } else if (!expr->IsNullOrUndefinedLiteral()) { 66351cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr); 66361cb0ef41Sopenharmony_ci BytecodeLabel is_null_or_undefined; 66371cb0ef41Sopenharmony_ci builder() 66381cb0ef41Sopenharmony_ci ->JumpIfUndefinedOrNull(&is_null_or_undefined) 66391cb0ef41Sopenharmony_ci .Jump(end_labels->New()); 66401cb0ef41Sopenharmony_ci builder()->Bind(&is_null_or_undefined); 66411cb0ef41Sopenharmony_ci } 66421cb0ef41Sopenharmony_ci 66431cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot); 66441cb0ef41Sopenharmony_ci 66451cb0ef41Sopenharmony_ci return false; 66461cb0ef41Sopenharmony_ci} 66471cb0ef41Sopenharmony_ci 66481cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { 66491cb0ef41Sopenharmony_ci Expression* left = binop->left(); 66501cb0ef41Sopenharmony_ci Expression* right = binop->right(); 66511cb0ef41Sopenharmony_ci 66521cb0ef41Sopenharmony_ci int right_coverage_slot = 66531cb0ef41Sopenharmony_ci AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight); 66541cb0ef41Sopenharmony_ci 66551cb0ef41Sopenharmony_ci if (execution_result()->IsTest()) { 66561cb0ef41Sopenharmony_ci TestResultScope* test_result = execution_result()->AsTest(); 66571cb0ef41Sopenharmony_ci if (left->ToBooleanIsTrue()) { 66581cb0ef41Sopenharmony_ci builder()->Jump(test_result->NewThenLabel()); 66591cb0ef41Sopenharmony_ci } else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) { 66601cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot); 66611cb0ef41Sopenharmony_ci builder()->Jump(test_result->NewElseLabel()); 66621cb0ef41Sopenharmony_ci } else { 66631cb0ef41Sopenharmony_ci VisitLogicalTest(Token::OR, left, right, right_coverage_slot); 66641cb0ef41Sopenharmony_ci } 66651cb0ef41Sopenharmony_ci test_result->SetResultConsumedByTest(); 66661cb0ef41Sopenharmony_ci } else { 66671cb0ef41Sopenharmony_ci BytecodeLabels end_labels(zone()); 66681cb0ef41Sopenharmony_ci if (VisitLogicalOrSubExpression(left, &end_labels, right_coverage_slot)) { 66691cb0ef41Sopenharmony_ci return; 66701cb0ef41Sopenharmony_ci } 66711cb0ef41Sopenharmony_ci VisitForAccumulatorValue(right); 66721cb0ef41Sopenharmony_ci end_labels.Bind(builder()); 66731cb0ef41Sopenharmony_ci } 66741cb0ef41Sopenharmony_ci} 66751cb0ef41Sopenharmony_ci 66761cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNaryLogicalOrExpression(NaryOperation* expr) { 66771cb0ef41Sopenharmony_ci Expression* first = expr->first(); 66781cb0ef41Sopenharmony_ci DCHECK_GT(expr->subsequent_length(), 0); 66791cb0ef41Sopenharmony_ci 66801cb0ef41Sopenharmony_ci NaryCodeCoverageSlots coverage_slots(this, expr); 66811cb0ef41Sopenharmony_ci 66821cb0ef41Sopenharmony_ci if (execution_result()->IsTest()) { 66831cb0ef41Sopenharmony_ci TestResultScope* test_result = execution_result()->AsTest(); 66841cb0ef41Sopenharmony_ci if (first->ToBooleanIsTrue()) { 66851cb0ef41Sopenharmony_ci builder()->Jump(test_result->NewThenLabel()); 66861cb0ef41Sopenharmony_ci } else { 66871cb0ef41Sopenharmony_ci VisitNaryLogicalTest(Token::OR, expr, &coverage_slots); 66881cb0ef41Sopenharmony_ci } 66891cb0ef41Sopenharmony_ci test_result->SetResultConsumedByTest(); 66901cb0ef41Sopenharmony_ci } else { 66911cb0ef41Sopenharmony_ci BytecodeLabels end_labels(zone()); 66921cb0ef41Sopenharmony_ci if (VisitLogicalOrSubExpression(first, &end_labels, 66931cb0ef41Sopenharmony_ci coverage_slots.GetSlotFor(0))) { 66941cb0ef41Sopenharmony_ci return; 66951cb0ef41Sopenharmony_ci } 66961cb0ef41Sopenharmony_ci for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) { 66971cb0ef41Sopenharmony_ci if (VisitLogicalOrSubExpression(expr->subsequent(i), &end_labels, 66981cb0ef41Sopenharmony_ci coverage_slots.GetSlotFor(i + 1))) { 66991cb0ef41Sopenharmony_ci return; 67001cb0ef41Sopenharmony_ci } 67011cb0ef41Sopenharmony_ci } 67021cb0ef41Sopenharmony_ci // We have to visit the last value even if it's true, because we need its 67031cb0ef41Sopenharmony_ci // actual value. 67041cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1)); 67051cb0ef41Sopenharmony_ci end_labels.Bind(builder()); 67061cb0ef41Sopenharmony_ci } 67071cb0ef41Sopenharmony_ci} 67081cb0ef41Sopenharmony_ci 67091cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { 67101cb0ef41Sopenharmony_ci Expression* left = binop->left(); 67111cb0ef41Sopenharmony_ci Expression* right = binop->right(); 67121cb0ef41Sopenharmony_ci 67131cb0ef41Sopenharmony_ci int right_coverage_slot = 67141cb0ef41Sopenharmony_ci AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight); 67151cb0ef41Sopenharmony_ci 67161cb0ef41Sopenharmony_ci if (execution_result()->IsTest()) { 67171cb0ef41Sopenharmony_ci TestResultScope* test_result = execution_result()->AsTest(); 67181cb0ef41Sopenharmony_ci if (left->ToBooleanIsFalse()) { 67191cb0ef41Sopenharmony_ci builder()->Jump(test_result->NewElseLabel()); 67201cb0ef41Sopenharmony_ci } else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) { 67211cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot); 67221cb0ef41Sopenharmony_ci builder()->Jump(test_result->NewThenLabel()); 67231cb0ef41Sopenharmony_ci } else { 67241cb0ef41Sopenharmony_ci VisitLogicalTest(Token::AND, left, right, right_coverage_slot); 67251cb0ef41Sopenharmony_ci } 67261cb0ef41Sopenharmony_ci test_result->SetResultConsumedByTest(); 67271cb0ef41Sopenharmony_ci } else { 67281cb0ef41Sopenharmony_ci BytecodeLabels end_labels(zone()); 67291cb0ef41Sopenharmony_ci if (VisitLogicalAndSubExpression(left, &end_labels, right_coverage_slot)) { 67301cb0ef41Sopenharmony_ci return; 67311cb0ef41Sopenharmony_ci } 67321cb0ef41Sopenharmony_ci VisitForAccumulatorValue(right); 67331cb0ef41Sopenharmony_ci end_labels.Bind(builder()); 67341cb0ef41Sopenharmony_ci } 67351cb0ef41Sopenharmony_ci} 67361cb0ef41Sopenharmony_ci 67371cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNaryLogicalAndExpression(NaryOperation* expr) { 67381cb0ef41Sopenharmony_ci Expression* first = expr->first(); 67391cb0ef41Sopenharmony_ci DCHECK_GT(expr->subsequent_length(), 0); 67401cb0ef41Sopenharmony_ci 67411cb0ef41Sopenharmony_ci NaryCodeCoverageSlots coverage_slots(this, expr); 67421cb0ef41Sopenharmony_ci 67431cb0ef41Sopenharmony_ci if (execution_result()->IsTest()) { 67441cb0ef41Sopenharmony_ci TestResultScope* test_result = execution_result()->AsTest(); 67451cb0ef41Sopenharmony_ci if (first->ToBooleanIsFalse()) { 67461cb0ef41Sopenharmony_ci builder()->Jump(test_result->NewElseLabel()); 67471cb0ef41Sopenharmony_ci } else { 67481cb0ef41Sopenharmony_ci VisitNaryLogicalTest(Token::AND, expr, &coverage_slots); 67491cb0ef41Sopenharmony_ci } 67501cb0ef41Sopenharmony_ci test_result->SetResultConsumedByTest(); 67511cb0ef41Sopenharmony_ci } else { 67521cb0ef41Sopenharmony_ci BytecodeLabels end_labels(zone()); 67531cb0ef41Sopenharmony_ci if (VisitLogicalAndSubExpression(first, &end_labels, 67541cb0ef41Sopenharmony_ci coverage_slots.GetSlotFor(0))) { 67551cb0ef41Sopenharmony_ci return; 67561cb0ef41Sopenharmony_ci } 67571cb0ef41Sopenharmony_ci for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) { 67581cb0ef41Sopenharmony_ci if (VisitLogicalAndSubExpression(expr->subsequent(i), &end_labels, 67591cb0ef41Sopenharmony_ci coverage_slots.GetSlotFor(i + 1))) { 67601cb0ef41Sopenharmony_ci return; 67611cb0ef41Sopenharmony_ci } 67621cb0ef41Sopenharmony_ci } 67631cb0ef41Sopenharmony_ci // We have to visit the last value even if it's false, because we need its 67641cb0ef41Sopenharmony_ci // actual value. 67651cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1)); 67661cb0ef41Sopenharmony_ci end_labels.Bind(builder()); 67671cb0ef41Sopenharmony_ci } 67681cb0ef41Sopenharmony_ci} 67691cb0ef41Sopenharmony_ci 67701cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNullishExpression(BinaryOperation* binop) { 67711cb0ef41Sopenharmony_ci Expression* left = binop->left(); 67721cb0ef41Sopenharmony_ci Expression* right = binop->right(); 67731cb0ef41Sopenharmony_ci 67741cb0ef41Sopenharmony_ci int right_coverage_slot = 67751cb0ef41Sopenharmony_ci AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight); 67761cb0ef41Sopenharmony_ci 67771cb0ef41Sopenharmony_ci if (execution_result()->IsTest()) { 67781cb0ef41Sopenharmony_ci TestResultScope* test_result = execution_result()->AsTest(); 67791cb0ef41Sopenharmony_ci if (left->IsLiteralButNotNullOrUndefined() && left->ToBooleanIsTrue()) { 67801cb0ef41Sopenharmony_ci builder()->Jump(test_result->NewThenLabel()); 67811cb0ef41Sopenharmony_ci } else if (left->IsNullOrUndefinedLiteral() && 67821cb0ef41Sopenharmony_ci right->IsNullOrUndefinedLiteral()) { 67831cb0ef41Sopenharmony_ci BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot); 67841cb0ef41Sopenharmony_ci builder()->Jump(test_result->NewElseLabel()); 67851cb0ef41Sopenharmony_ci } else { 67861cb0ef41Sopenharmony_ci VisitLogicalTest(Token::NULLISH, left, right, right_coverage_slot); 67871cb0ef41Sopenharmony_ci } 67881cb0ef41Sopenharmony_ci test_result->SetResultConsumedByTest(); 67891cb0ef41Sopenharmony_ci } else { 67901cb0ef41Sopenharmony_ci BytecodeLabels end_labels(zone()); 67911cb0ef41Sopenharmony_ci if (VisitNullishSubExpression(left, &end_labels, right_coverage_slot)) { 67921cb0ef41Sopenharmony_ci return; 67931cb0ef41Sopenharmony_ci } 67941cb0ef41Sopenharmony_ci VisitForAccumulatorValue(right); 67951cb0ef41Sopenharmony_ci end_labels.Bind(builder()); 67961cb0ef41Sopenharmony_ci } 67971cb0ef41Sopenharmony_ci} 67981cb0ef41Sopenharmony_ci 67991cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNaryNullishExpression(NaryOperation* expr) { 68001cb0ef41Sopenharmony_ci Expression* first = expr->first(); 68011cb0ef41Sopenharmony_ci DCHECK_GT(expr->subsequent_length(), 0); 68021cb0ef41Sopenharmony_ci 68031cb0ef41Sopenharmony_ci NaryCodeCoverageSlots coverage_slots(this, expr); 68041cb0ef41Sopenharmony_ci 68051cb0ef41Sopenharmony_ci if (execution_result()->IsTest()) { 68061cb0ef41Sopenharmony_ci TestResultScope* test_result = execution_result()->AsTest(); 68071cb0ef41Sopenharmony_ci if (first->IsLiteralButNotNullOrUndefined() && first->ToBooleanIsTrue()) { 68081cb0ef41Sopenharmony_ci builder()->Jump(test_result->NewThenLabel()); 68091cb0ef41Sopenharmony_ci } else { 68101cb0ef41Sopenharmony_ci VisitNaryLogicalTest(Token::NULLISH, expr, &coverage_slots); 68111cb0ef41Sopenharmony_ci } 68121cb0ef41Sopenharmony_ci test_result->SetResultConsumedByTest(); 68131cb0ef41Sopenharmony_ci } else { 68141cb0ef41Sopenharmony_ci BytecodeLabels end_labels(zone()); 68151cb0ef41Sopenharmony_ci if (VisitNullishSubExpression(first, &end_labels, 68161cb0ef41Sopenharmony_ci coverage_slots.GetSlotFor(0))) { 68171cb0ef41Sopenharmony_ci return; 68181cb0ef41Sopenharmony_ci } 68191cb0ef41Sopenharmony_ci for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) { 68201cb0ef41Sopenharmony_ci if (VisitNullishSubExpression(expr->subsequent(i), &end_labels, 68211cb0ef41Sopenharmony_ci coverage_slots.GetSlotFor(i + 1))) { 68221cb0ef41Sopenharmony_ci return; 68231cb0ef41Sopenharmony_ci } 68241cb0ef41Sopenharmony_ci } 68251cb0ef41Sopenharmony_ci // We have to visit the last value even if it's nullish, because we need its 68261cb0ef41Sopenharmony_ci // actual value. 68271cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1)); 68281cb0ef41Sopenharmony_ci end_labels.Bind(builder()); 68291cb0ef41Sopenharmony_ci } 68301cb0ef41Sopenharmony_ci} 68311cb0ef41Sopenharmony_ci 68321cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildNewLocalActivationContext() { 68331cb0ef41Sopenharmony_ci ValueResultScope value_execution_result(this); 68341cb0ef41Sopenharmony_ci Scope* scope = closure_scope(); 68351cb0ef41Sopenharmony_ci DCHECK_EQ(current_scope(), closure_scope()); 68361cb0ef41Sopenharmony_ci 68371cb0ef41Sopenharmony_ci // Create the appropriate context. 68381cb0ef41Sopenharmony_ci DCHECK(scope->is_function_scope() || scope->is_eval_scope()); 68391cb0ef41Sopenharmony_ci int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 68401cb0ef41Sopenharmony_ci if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) { 68411cb0ef41Sopenharmony_ci switch (scope->scope_type()) { 68421cb0ef41Sopenharmony_ci case EVAL_SCOPE: 68431cb0ef41Sopenharmony_ci builder()->CreateEvalContext(scope, slot_count); 68441cb0ef41Sopenharmony_ci break; 68451cb0ef41Sopenharmony_ci case FUNCTION_SCOPE: 68461cb0ef41Sopenharmony_ci builder()->CreateFunctionContext(scope, slot_count); 68471cb0ef41Sopenharmony_ci break; 68481cb0ef41Sopenharmony_ci default: 68491cb0ef41Sopenharmony_ci UNREACHABLE(); 68501cb0ef41Sopenharmony_ci } 68511cb0ef41Sopenharmony_ci } else { 68521cb0ef41Sopenharmony_ci Register arg = register_allocator()->NewRegister(); 68531cb0ef41Sopenharmony_ci builder()->LoadLiteral(scope).StoreAccumulatorInRegister(arg).CallRuntime( 68541cb0ef41Sopenharmony_ci Runtime::kNewFunctionContext, arg); 68551cb0ef41Sopenharmony_ci } 68561cb0ef41Sopenharmony_ci} 68571cb0ef41Sopenharmony_ci 68581cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildLocalActivationContextInitialization() { 68591cb0ef41Sopenharmony_ci DeclarationScope* scope = closure_scope(); 68601cb0ef41Sopenharmony_ci 68611cb0ef41Sopenharmony_ci if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { 68621cb0ef41Sopenharmony_ci Variable* variable = scope->receiver(); 68631cb0ef41Sopenharmony_ci Register receiver(builder()->Receiver()); 68641cb0ef41Sopenharmony_ci // Context variable (at bottom of the context chain). 68651cb0ef41Sopenharmony_ci DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); 68661cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(receiver).StoreContextSlot( 68671cb0ef41Sopenharmony_ci execution_context()->reg(), variable->index(), 0); 68681cb0ef41Sopenharmony_ci } 68691cb0ef41Sopenharmony_ci 68701cb0ef41Sopenharmony_ci // Copy parameters into context if necessary. 68711cb0ef41Sopenharmony_ci int num_parameters = scope->num_parameters(); 68721cb0ef41Sopenharmony_ci for (int i = 0; i < num_parameters; i++) { 68731cb0ef41Sopenharmony_ci Variable* variable = scope->parameter(i); 68741cb0ef41Sopenharmony_ci if (!variable->IsContextSlot()) continue; 68751cb0ef41Sopenharmony_ci 68761cb0ef41Sopenharmony_ci Register parameter(builder()->Parameter(i)); 68771cb0ef41Sopenharmony_ci // Context variable (at bottom of the context chain). 68781cb0ef41Sopenharmony_ci DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); 68791cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(parameter).StoreContextSlot( 68801cb0ef41Sopenharmony_ci execution_context()->reg(), variable->index(), 0); 68811cb0ef41Sopenharmony_ci } 68821cb0ef41Sopenharmony_ci} 68831cb0ef41Sopenharmony_ci 68841cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildNewLocalBlockContext(Scope* scope) { 68851cb0ef41Sopenharmony_ci ValueResultScope value_execution_result(this); 68861cb0ef41Sopenharmony_ci DCHECK(scope->is_block_scope()); 68871cb0ef41Sopenharmony_ci 68881cb0ef41Sopenharmony_ci builder()->CreateBlockContext(scope); 68891cb0ef41Sopenharmony_ci} 68901cb0ef41Sopenharmony_ci 68911cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildNewLocalWithContext(Scope* scope) { 68921cb0ef41Sopenharmony_ci ValueResultScope value_execution_result(this); 68931cb0ef41Sopenharmony_ci 68941cb0ef41Sopenharmony_ci Register extension_object = register_allocator()->NewRegister(); 68951cb0ef41Sopenharmony_ci 68961cb0ef41Sopenharmony_ci builder()->ToObject(extension_object); 68971cb0ef41Sopenharmony_ci builder()->CreateWithContext(extension_object, scope); 68981cb0ef41Sopenharmony_ci} 68991cb0ef41Sopenharmony_ci 69001cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildNewLocalCatchContext(Scope* scope) { 69011cb0ef41Sopenharmony_ci ValueResultScope value_execution_result(this); 69021cb0ef41Sopenharmony_ci DCHECK(scope->catch_variable()->IsContextSlot()); 69031cb0ef41Sopenharmony_ci 69041cb0ef41Sopenharmony_ci Register exception = register_allocator()->NewRegister(); 69051cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(exception); 69061cb0ef41Sopenharmony_ci builder()->CreateCatchContext(exception, scope); 69071cb0ef41Sopenharmony_ci} 69081cb0ef41Sopenharmony_ci 69091cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitLiteralAccessor(LiteralProperty* property, 69101cb0ef41Sopenharmony_ci Register value_out) { 69111cb0ef41Sopenharmony_ci if (property == nullptr) { 69121cb0ef41Sopenharmony_ci builder()->LoadNull().StoreAccumulatorInRegister(value_out); 69131cb0ef41Sopenharmony_ci } else { 69141cb0ef41Sopenharmony_ci VisitForRegisterValue(property->value(), value_out); 69151cb0ef41Sopenharmony_ci } 69161cb0ef41Sopenharmony_ci} 69171cb0ef41Sopenharmony_ci 69181cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitArgumentsObject(Variable* variable) { 69191cb0ef41Sopenharmony_ci if (variable == nullptr) return; 69201cb0ef41Sopenharmony_ci 69211cb0ef41Sopenharmony_ci DCHECK(variable->IsContextSlot() || variable->IsStackAllocated()); 69221cb0ef41Sopenharmony_ci 69231cb0ef41Sopenharmony_ci // Allocate and initialize a new arguments object and assign to the 69241cb0ef41Sopenharmony_ci // {arguments} variable. 69251cb0ef41Sopenharmony_ci builder()->CreateArguments(closure_scope()->GetArgumentsType()); 69261cb0ef41Sopenharmony_ci BuildVariableAssignment(variable, Token::ASSIGN, HoleCheckMode::kElided); 69271cb0ef41Sopenharmony_ci} 69281cb0ef41Sopenharmony_ci 69291cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) { 69301cb0ef41Sopenharmony_ci if (rest == nullptr) return; 69311cb0ef41Sopenharmony_ci 69321cb0ef41Sopenharmony_ci // Allocate and initialize a new rest parameter and assign to the {rest} 69331cb0ef41Sopenharmony_ci // variable. 69341cb0ef41Sopenharmony_ci builder()->CreateArguments(CreateArgumentsType::kRestParameter); 69351cb0ef41Sopenharmony_ci DCHECK(rest->IsContextSlot() || rest->IsStackAllocated()); 69361cb0ef41Sopenharmony_ci BuildVariableAssignment(rest, Token::ASSIGN, HoleCheckMode::kElided); 69371cb0ef41Sopenharmony_ci} 69381cb0ef41Sopenharmony_ci 69391cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) { 69401cb0ef41Sopenharmony_ci if (variable == nullptr) return; 69411cb0ef41Sopenharmony_ci 69421cb0ef41Sopenharmony_ci // Store the closure we were called with in the given variable. 69431cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(Register::function_closure()); 69441cb0ef41Sopenharmony_ci BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided); 69451cb0ef41Sopenharmony_ci} 69461cb0ef41Sopenharmony_ci 69471cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { 69481cb0ef41Sopenharmony_ci if (variable == nullptr) return; 69491cb0ef41Sopenharmony_ci 69501cb0ef41Sopenharmony_ci // The generator resume trampoline abuses the new.target register 69511cb0ef41Sopenharmony_ci // to pass in the generator object. In ordinary calls, new.target is always 69521cb0ef41Sopenharmony_ci // undefined because generator functions are non-constructible, so don't 69531cb0ef41Sopenharmony_ci // assign anything to the new.target variable. 69541cb0ef41Sopenharmony_ci if (IsResumableFunction(info()->literal()->kind())) return; 69551cb0ef41Sopenharmony_ci 69561cb0ef41Sopenharmony_ci if (variable->location() == VariableLocation::LOCAL) { 69571cb0ef41Sopenharmony_ci // The new.target register was already assigned by entry trampoline. 69581cb0ef41Sopenharmony_ci DCHECK_EQ(incoming_new_target_or_generator_.index(), 69591cb0ef41Sopenharmony_ci GetRegisterForLocalVariable(variable).index()); 69601cb0ef41Sopenharmony_ci return; 69611cb0ef41Sopenharmony_ci } 69621cb0ef41Sopenharmony_ci 69631cb0ef41Sopenharmony_ci // Store the new target we were called with in the given variable. 69641cb0ef41Sopenharmony_ci builder()->LoadAccumulatorWithRegister(incoming_new_target_or_generator_); 69651cb0ef41Sopenharmony_ci BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided); 69661cb0ef41Sopenharmony_ci} 69671cb0ef41Sopenharmony_ci 69681cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildGeneratorObjectVariableInitialization() { 69691cb0ef41Sopenharmony_ci DCHECK(IsResumableFunction(info()->literal()->kind())); 69701cb0ef41Sopenharmony_ci 69711cb0ef41Sopenharmony_ci Variable* generator_object_var = closure_scope()->generator_object_var(); 69721cb0ef41Sopenharmony_ci RegisterAllocationScope register_scope(this); 69731cb0ef41Sopenharmony_ci RegisterList args = register_allocator()->NewRegisterList(2); 69741cb0ef41Sopenharmony_ci Runtime::FunctionId function_id = 69751cb0ef41Sopenharmony_ci ((IsAsyncFunction(info()->literal()->kind()) && 69761cb0ef41Sopenharmony_ci !IsAsyncGeneratorFunction(info()->literal()->kind())) || 69771cb0ef41Sopenharmony_ci IsAsyncModule(info()->literal()->kind())) 69781cb0ef41Sopenharmony_ci ? Runtime::kInlineAsyncFunctionEnter 69791cb0ef41Sopenharmony_ci : Runtime::kInlineCreateJSGeneratorObject; 69801cb0ef41Sopenharmony_ci builder() 69811cb0ef41Sopenharmony_ci ->MoveRegister(Register::function_closure(), args[0]) 69821cb0ef41Sopenharmony_ci .MoveRegister(builder()->Receiver(), args[1]) 69831cb0ef41Sopenharmony_ci .CallRuntime(function_id, args) 69841cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(generator_object()); 69851cb0ef41Sopenharmony_ci 69861cb0ef41Sopenharmony_ci if (generator_object_var->location() == VariableLocation::LOCAL) { 69871cb0ef41Sopenharmony_ci // The generator object register is already set to the variable's local 69881cb0ef41Sopenharmony_ci // register. 69891cb0ef41Sopenharmony_ci DCHECK_EQ(generator_object().index(), 69901cb0ef41Sopenharmony_ci GetRegisterForLocalVariable(generator_object_var).index()); 69911cb0ef41Sopenharmony_ci } else { 69921cb0ef41Sopenharmony_ci BuildVariableAssignment(generator_object_var, Token::INIT, 69931cb0ef41Sopenharmony_ci HoleCheckMode::kElided); 69941cb0ef41Sopenharmony_ci } 69951cb0ef41Sopenharmony_ci} 69961cb0ef41Sopenharmony_ci 69971cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildPushUndefinedIntoRegisterList( 69981cb0ef41Sopenharmony_ci RegisterList* reg_list) { 69991cb0ef41Sopenharmony_ci Register reg = register_allocator()->GrowRegisterList(reg_list); 70001cb0ef41Sopenharmony_ci builder()->LoadUndefined().StoreAccumulatorInRegister(reg); 70011cb0ef41Sopenharmony_ci} 70021cb0ef41Sopenharmony_ci 70031cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildLoadPropertyKey(LiteralProperty* property, 70041cb0ef41Sopenharmony_ci Register out_reg) { 70051cb0ef41Sopenharmony_ci if (property->key()->IsStringLiteral()) { 70061cb0ef41Sopenharmony_ci builder() 70071cb0ef41Sopenharmony_ci ->LoadLiteral(property->key()->AsLiteral()->AsRawString()) 70081cb0ef41Sopenharmony_ci .StoreAccumulatorInRegister(out_reg); 70091cb0ef41Sopenharmony_ci } else { 70101cb0ef41Sopenharmony_ci VisitForAccumulatorValue(property->key()); 70111cb0ef41Sopenharmony_ci builder()->ToName(out_reg); 70121cb0ef41Sopenharmony_ci } 70131cb0ef41Sopenharmony_ci} 70141cb0ef41Sopenharmony_ci 70151cb0ef41Sopenharmony_ciint BytecodeGenerator::AllocateBlockCoverageSlotIfEnabled( 70161cb0ef41Sopenharmony_ci AstNode* node, SourceRangeKind kind) { 70171cb0ef41Sopenharmony_ci return (block_coverage_builder_ == nullptr) 70181cb0ef41Sopenharmony_ci ? BlockCoverageBuilder::kNoCoverageArraySlot 70191cb0ef41Sopenharmony_ci : block_coverage_builder_->AllocateBlockCoverageSlot(node, kind); 70201cb0ef41Sopenharmony_ci} 70211cb0ef41Sopenharmony_ci 70221cb0ef41Sopenharmony_ciint BytecodeGenerator::AllocateNaryBlockCoverageSlotIfEnabled( 70231cb0ef41Sopenharmony_ci NaryOperation* node, size_t index) { 70241cb0ef41Sopenharmony_ci return (block_coverage_builder_ == nullptr) 70251cb0ef41Sopenharmony_ci ? BlockCoverageBuilder::kNoCoverageArraySlot 70261cb0ef41Sopenharmony_ci : block_coverage_builder_->AllocateNaryBlockCoverageSlot(node, 70271cb0ef41Sopenharmony_ci index); 70281cb0ef41Sopenharmony_ci} 70291cb0ef41Sopenharmony_ci 70301cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled( 70311cb0ef41Sopenharmony_ci AstNode* node, SourceRangeKind kind) { 70321cb0ef41Sopenharmony_ci if (block_coverage_builder_ == nullptr) return; 70331cb0ef41Sopenharmony_ci block_coverage_builder_->IncrementBlockCounter(node, kind); 70341cb0ef41Sopenharmony_ci} 70351cb0ef41Sopenharmony_ci 70361cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled( 70371cb0ef41Sopenharmony_ci int coverage_array_slot) { 70381cb0ef41Sopenharmony_ci if (block_coverage_builder_ != nullptr) { 70391cb0ef41Sopenharmony_ci block_coverage_builder_->IncrementBlockCounter(coverage_array_slot); 70401cb0ef41Sopenharmony_ci } 70411cb0ef41Sopenharmony_ci} 70421cb0ef41Sopenharmony_ci 70431cb0ef41Sopenharmony_ci// Visits the expression |expr| and places the result in the accumulator. 70441cb0ef41Sopenharmony_ciBytecodeGenerator::TypeHint BytecodeGenerator::VisitForAccumulatorValue( 70451cb0ef41Sopenharmony_ci Expression* expr) { 70461cb0ef41Sopenharmony_ci ValueResultScope accumulator_scope(this); 70471cb0ef41Sopenharmony_ci Visit(expr); 70481cb0ef41Sopenharmony_ci return accumulator_scope.type_hint(); 70491cb0ef41Sopenharmony_ci} 70501cb0ef41Sopenharmony_ci 70511cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) { 70521cb0ef41Sopenharmony_ci if (expr == nullptr) { 70531cb0ef41Sopenharmony_ci builder()->LoadTheHole(); 70541cb0ef41Sopenharmony_ci } else { 70551cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr); 70561cb0ef41Sopenharmony_ci } 70571cb0ef41Sopenharmony_ci} 70581cb0ef41Sopenharmony_ci 70591cb0ef41Sopenharmony_ci// Visits the expression |expr| and discards the result. 70601cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitForEffect(Expression* expr) { 70611cb0ef41Sopenharmony_ci EffectResultScope effect_scope(this); 70621cb0ef41Sopenharmony_ci Visit(expr); 70631cb0ef41Sopenharmony_ci} 70641cb0ef41Sopenharmony_ci 70651cb0ef41Sopenharmony_ci// Visits the expression |expr| and returns the register containing 70661cb0ef41Sopenharmony_ci// the expression result. 70671cb0ef41Sopenharmony_ciRegister BytecodeGenerator::VisitForRegisterValue(Expression* expr) { 70681cb0ef41Sopenharmony_ci VisitForAccumulatorValue(expr); 70691cb0ef41Sopenharmony_ci Register result = register_allocator()->NewRegister(); 70701cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(result); 70711cb0ef41Sopenharmony_ci return result; 70721cb0ef41Sopenharmony_ci} 70731cb0ef41Sopenharmony_ci 70741cb0ef41Sopenharmony_ci// Visits the expression |expr| and stores the expression result in 70751cb0ef41Sopenharmony_ci// |destination|. 70761cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitForRegisterValue(Expression* expr, 70771cb0ef41Sopenharmony_ci Register destination) { 70781cb0ef41Sopenharmony_ci ValueResultScope register_scope(this); 70791cb0ef41Sopenharmony_ci Visit(expr); 70801cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(destination); 70811cb0ef41Sopenharmony_ci} 70821cb0ef41Sopenharmony_ci 70831cb0ef41Sopenharmony_ci// Visits the expression |expr| and pushes the result into a new register 70841cb0ef41Sopenharmony_ci// added to the end of |reg_list|. 70851cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitAndPushIntoRegisterList(Expression* expr, 70861cb0ef41Sopenharmony_ci RegisterList* reg_list) { 70871cb0ef41Sopenharmony_ci { 70881cb0ef41Sopenharmony_ci ValueResultScope register_scope(this); 70891cb0ef41Sopenharmony_ci Visit(expr); 70901cb0ef41Sopenharmony_ci } 70911cb0ef41Sopenharmony_ci // Grow the register list after visiting the expression to avoid reserving 70921cb0ef41Sopenharmony_ci // the register across the expression evaluation, which could cause memory 70931cb0ef41Sopenharmony_ci // leaks for deep expressions due to dead objects being kept alive by pointers 70941cb0ef41Sopenharmony_ci // in registers. 70951cb0ef41Sopenharmony_ci Register destination = register_allocator()->GrowRegisterList(reg_list); 70961cb0ef41Sopenharmony_ci builder()->StoreAccumulatorInRegister(destination); 70971cb0ef41Sopenharmony_ci} 70981cb0ef41Sopenharmony_ci 70991cb0ef41Sopenharmony_civoid BytecodeGenerator::BuildTest(ToBooleanMode mode, 71001cb0ef41Sopenharmony_ci BytecodeLabels* then_labels, 71011cb0ef41Sopenharmony_ci BytecodeLabels* else_labels, 71021cb0ef41Sopenharmony_ci TestFallthrough fallthrough) { 71031cb0ef41Sopenharmony_ci switch (fallthrough) { 71041cb0ef41Sopenharmony_ci case TestFallthrough::kThen: 71051cb0ef41Sopenharmony_ci builder()->JumpIfFalse(mode, else_labels->New()); 71061cb0ef41Sopenharmony_ci break; 71071cb0ef41Sopenharmony_ci case TestFallthrough::kElse: 71081cb0ef41Sopenharmony_ci builder()->JumpIfTrue(mode, then_labels->New()); 71091cb0ef41Sopenharmony_ci break; 71101cb0ef41Sopenharmony_ci case TestFallthrough::kNone: 71111cb0ef41Sopenharmony_ci builder()->JumpIfTrue(mode, then_labels->New()); 71121cb0ef41Sopenharmony_ci builder()->Jump(else_labels->New()); 71131cb0ef41Sopenharmony_ci break; 71141cb0ef41Sopenharmony_ci } 71151cb0ef41Sopenharmony_ci} 71161cb0ef41Sopenharmony_ci 71171cb0ef41Sopenharmony_ci// Visits the expression |expr| for testing its boolean value and jumping to the 71181cb0ef41Sopenharmony_ci// |then| or |other| label depending on value and short-circuit semantics 71191cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitForTest(Expression* expr, 71201cb0ef41Sopenharmony_ci BytecodeLabels* then_labels, 71211cb0ef41Sopenharmony_ci BytecodeLabels* else_labels, 71221cb0ef41Sopenharmony_ci TestFallthrough fallthrough) { 71231cb0ef41Sopenharmony_ci bool result_consumed; 71241cb0ef41Sopenharmony_ci TypeHint type_hint; 71251cb0ef41Sopenharmony_ci { 71261cb0ef41Sopenharmony_ci // To make sure that all temporary registers are returned before generating 71271cb0ef41Sopenharmony_ci // jumps below, we ensure that the result scope is deleted before doing so. 71281cb0ef41Sopenharmony_ci // Dead registers might be materialized otherwise. 71291cb0ef41Sopenharmony_ci TestResultScope test_result(this, then_labels, else_labels, fallthrough); 71301cb0ef41Sopenharmony_ci Visit(expr); 71311cb0ef41Sopenharmony_ci result_consumed = test_result.result_consumed_by_test(); 71321cb0ef41Sopenharmony_ci type_hint = test_result.type_hint(); 71331cb0ef41Sopenharmony_ci // Labels and fallthrough might have been mutated, so update based on 71341cb0ef41Sopenharmony_ci // TestResultScope. 71351cb0ef41Sopenharmony_ci then_labels = test_result.then_labels(); 71361cb0ef41Sopenharmony_ci else_labels = test_result.else_labels(); 71371cb0ef41Sopenharmony_ci fallthrough = test_result.fallthrough(); 71381cb0ef41Sopenharmony_ci } 71391cb0ef41Sopenharmony_ci if (!result_consumed) { 71401cb0ef41Sopenharmony_ci BuildTest(ToBooleanModeFromTypeHint(type_hint), then_labels, else_labels, 71411cb0ef41Sopenharmony_ci fallthrough); 71421cb0ef41Sopenharmony_ci } 71431cb0ef41Sopenharmony_ci} 71441cb0ef41Sopenharmony_ci 71451cb0ef41Sopenharmony_ci// Visits the expression |expr| for testing its nullish value and jumping to the 71461cb0ef41Sopenharmony_ci// |then| or |other| label depending on value and short-circuit semantics 71471cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitForNullishTest(Expression* expr, 71481cb0ef41Sopenharmony_ci BytecodeLabels* then_labels, 71491cb0ef41Sopenharmony_ci BytecodeLabels* test_next_labels, 71501cb0ef41Sopenharmony_ci BytecodeLabels* else_labels) { 71511cb0ef41Sopenharmony_ci // Nullish short circuits on undefined or null, otherwise we fall back to 71521cb0ef41Sopenharmony_ci // BuildTest with no fallthrough. 71531cb0ef41Sopenharmony_ci // TODO(joshualitt): We should do this in a TestResultScope. 71541cb0ef41Sopenharmony_ci TypeHint type_hint = VisitForAccumulatorValue(expr); 71551cb0ef41Sopenharmony_ci ToBooleanMode mode = ToBooleanModeFromTypeHint(type_hint); 71561cb0ef41Sopenharmony_ci 71571cb0ef41Sopenharmony_ci // Skip the nullish shortcircuit if we already have a boolean. 71581cb0ef41Sopenharmony_ci if (mode != ToBooleanMode::kAlreadyBoolean) { 71591cb0ef41Sopenharmony_ci builder()->JumpIfUndefinedOrNull(test_next_labels->New()); 71601cb0ef41Sopenharmony_ci } 71611cb0ef41Sopenharmony_ci BuildTest(mode, then_labels, else_labels, TestFallthrough::kNone); 71621cb0ef41Sopenharmony_ci} 71631cb0ef41Sopenharmony_ci 71641cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitInSameTestExecutionScope(Expression* expr) { 71651cb0ef41Sopenharmony_ci DCHECK(execution_result()->IsTest()); 71661cb0ef41Sopenharmony_ci { 71671cb0ef41Sopenharmony_ci RegisterAllocationScope reg_scope(this); 71681cb0ef41Sopenharmony_ci Visit(expr); 71691cb0ef41Sopenharmony_ci } 71701cb0ef41Sopenharmony_ci if (!execution_result()->AsTest()->result_consumed_by_test()) { 71711cb0ef41Sopenharmony_ci TestResultScope* result_scope = execution_result()->AsTest(); 71721cb0ef41Sopenharmony_ci BuildTest(ToBooleanModeFromTypeHint(result_scope->type_hint()), 71731cb0ef41Sopenharmony_ci result_scope->then_labels(), result_scope->else_labels(), 71741cb0ef41Sopenharmony_ci result_scope->fallthrough()); 71751cb0ef41Sopenharmony_ci result_scope->SetResultConsumedByTest(); 71761cb0ef41Sopenharmony_ci } 71771cb0ef41Sopenharmony_ci} 71781cb0ef41Sopenharmony_ci 71791cb0ef41Sopenharmony_civoid BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) { 71801cb0ef41Sopenharmony_ci DCHECK(scope->declarations()->is_empty()); 71811cb0ef41Sopenharmony_ci CurrentScope current_scope(this, scope); 71821cb0ef41Sopenharmony_ci ContextScope context_scope(this, scope); 71831cb0ef41Sopenharmony_ci Visit(stmt); 71841cb0ef41Sopenharmony_ci} 71851cb0ef41Sopenharmony_ci 71861cb0ef41Sopenharmony_ciRegister BytecodeGenerator::GetRegisterForLocalVariable(Variable* variable) { 71871cb0ef41Sopenharmony_ci DCHECK_EQ(VariableLocation::LOCAL, variable->location()); 71881cb0ef41Sopenharmony_ci return builder()->Local(variable->index()); 71891cb0ef41Sopenharmony_ci} 71901cb0ef41Sopenharmony_ci 71911cb0ef41Sopenharmony_ciFunctionKind BytecodeGenerator::function_kind() const { 71921cb0ef41Sopenharmony_ci return info()->literal()->kind(); 71931cb0ef41Sopenharmony_ci} 71941cb0ef41Sopenharmony_ci 71951cb0ef41Sopenharmony_ciLanguageMode BytecodeGenerator::language_mode() const { 71961cb0ef41Sopenharmony_ci return current_scope()->language_mode(); 71971cb0ef41Sopenharmony_ci} 71981cb0ef41Sopenharmony_ci 71991cb0ef41Sopenharmony_ciRegister BytecodeGenerator::generator_object() const { 72001cb0ef41Sopenharmony_ci DCHECK(IsResumableFunction(info()->literal()->kind())); 72011cb0ef41Sopenharmony_ci return incoming_new_target_or_generator_; 72021cb0ef41Sopenharmony_ci} 72031cb0ef41Sopenharmony_ci 72041cb0ef41Sopenharmony_ciFeedbackVectorSpec* BytecodeGenerator::feedback_spec() { 72051cb0ef41Sopenharmony_ci return info()->feedback_vector_spec(); 72061cb0ef41Sopenharmony_ci} 72071cb0ef41Sopenharmony_ci 72081cb0ef41Sopenharmony_ciint BytecodeGenerator::feedback_index(FeedbackSlot slot) const { 72091cb0ef41Sopenharmony_ci DCHECK(!slot.IsInvalid()); 72101cb0ef41Sopenharmony_ci return FeedbackVector::GetIndex(slot); 72111cb0ef41Sopenharmony_ci} 72121cb0ef41Sopenharmony_ci 72131cb0ef41Sopenharmony_ciFeedbackSlot BytecodeGenerator::GetCachedLoadGlobalICSlot( 72141cb0ef41Sopenharmony_ci TypeofMode typeof_mode, Variable* variable) { 72151cb0ef41Sopenharmony_ci FeedbackSlotCache::SlotKind slot_kind = 72161cb0ef41Sopenharmony_ci typeof_mode == TypeofMode::kInside 72171cb0ef41Sopenharmony_ci ? FeedbackSlotCache::SlotKind::kLoadGlobalInsideTypeof 72181cb0ef41Sopenharmony_ci : FeedbackSlotCache::SlotKind::kLoadGlobalNotInsideTypeof; 72191cb0ef41Sopenharmony_ci FeedbackSlot slot(feedback_slot_cache()->Get(slot_kind, variable)); 72201cb0ef41Sopenharmony_ci if (!slot.IsInvalid()) { 72211cb0ef41Sopenharmony_ci return slot; 72221cb0ef41Sopenharmony_ci } 72231cb0ef41Sopenharmony_ci slot = feedback_spec()->AddLoadGlobalICSlot(typeof_mode); 72241cb0ef41Sopenharmony_ci feedback_slot_cache()->Put(slot_kind, variable, feedback_index(slot)); 72251cb0ef41Sopenharmony_ci return slot; 72261cb0ef41Sopenharmony_ci} 72271cb0ef41Sopenharmony_ci 72281cb0ef41Sopenharmony_ciFeedbackSlot BytecodeGenerator::GetCachedStoreGlobalICSlot( 72291cb0ef41Sopenharmony_ci LanguageMode language_mode, Variable* variable) { 72301cb0ef41Sopenharmony_ci FeedbackSlotCache::SlotKind slot_kind = 72311cb0ef41Sopenharmony_ci is_strict(language_mode) 72321cb0ef41Sopenharmony_ci ? FeedbackSlotCache::SlotKind::kStoreGlobalStrict 72331cb0ef41Sopenharmony_ci : FeedbackSlotCache::SlotKind::kStoreGlobalSloppy; 72341cb0ef41Sopenharmony_ci FeedbackSlot slot(feedback_slot_cache()->Get(slot_kind, variable)); 72351cb0ef41Sopenharmony_ci if (!slot.IsInvalid()) { 72361cb0ef41Sopenharmony_ci return slot; 72371cb0ef41Sopenharmony_ci } 72381cb0ef41Sopenharmony_ci slot = feedback_spec()->AddStoreGlobalICSlot(language_mode); 72391cb0ef41Sopenharmony_ci feedback_slot_cache()->Put(slot_kind, variable, feedback_index(slot)); 72401cb0ef41Sopenharmony_ci return slot; 72411cb0ef41Sopenharmony_ci} 72421cb0ef41Sopenharmony_ci 72431cb0ef41Sopenharmony_ciFeedbackSlot BytecodeGenerator::GetCachedLoadICSlot(const Expression* expr, 72441cb0ef41Sopenharmony_ci const AstRawString* name) { 72451cb0ef41Sopenharmony_ci DCHECK(!expr->IsSuperPropertyReference()); 72461cb0ef41Sopenharmony_ci if (!FLAG_ignition_share_named_property_feedback) { 72471cb0ef41Sopenharmony_ci return feedback_spec()->AddLoadICSlot(); 72481cb0ef41Sopenharmony_ci } 72491cb0ef41Sopenharmony_ci FeedbackSlotCache::SlotKind slot_kind = 72501cb0ef41Sopenharmony_ci FeedbackSlotCache::SlotKind::kLoadProperty; 72511cb0ef41Sopenharmony_ci if (!expr->IsVariableProxy()) { 72521cb0ef41Sopenharmony_ci return feedback_spec()->AddLoadICSlot(); 72531cb0ef41Sopenharmony_ci } 72541cb0ef41Sopenharmony_ci const VariableProxy* proxy = expr->AsVariableProxy(); 72551cb0ef41Sopenharmony_ci FeedbackSlot slot( 72561cb0ef41Sopenharmony_ci feedback_slot_cache()->Get(slot_kind, proxy->var()->index(), name)); 72571cb0ef41Sopenharmony_ci if (!slot.IsInvalid()) { 72581cb0ef41Sopenharmony_ci return slot; 72591cb0ef41Sopenharmony_ci } 72601cb0ef41Sopenharmony_ci slot = feedback_spec()->AddLoadICSlot(); 72611cb0ef41Sopenharmony_ci feedback_slot_cache()->Put(slot_kind, proxy->var()->index(), name, 72621cb0ef41Sopenharmony_ci feedback_index(slot)); 72631cb0ef41Sopenharmony_ci return slot; 72641cb0ef41Sopenharmony_ci} 72651cb0ef41Sopenharmony_ci 72661cb0ef41Sopenharmony_ciFeedbackSlot BytecodeGenerator::GetCachedLoadSuperICSlot( 72671cb0ef41Sopenharmony_ci const AstRawString* name) { 72681cb0ef41Sopenharmony_ci if (!FLAG_ignition_share_named_property_feedback) { 72691cb0ef41Sopenharmony_ci return feedback_spec()->AddLoadICSlot(); 72701cb0ef41Sopenharmony_ci } 72711cb0ef41Sopenharmony_ci FeedbackSlotCache::SlotKind slot_kind = 72721cb0ef41Sopenharmony_ci FeedbackSlotCache::SlotKind::kLoadSuperProperty; 72731cb0ef41Sopenharmony_ci 72741cb0ef41Sopenharmony_ci FeedbackSlot slot(feedback_slot_cache()->Get(slot_kind, name)); 72751cb0ef41Sopenharmony_ci if (!slot.IsInvalid()) { 72761cb0ef41Sopenharmony_ci return slot; 72771cb0ef41Sopenharmony_ci } 72781cb0ef41Sopenharmony_ci slot = feedback_spec()->AddLoadICSlot(); 72791cb0ef41Sopenharmony_ci feedback_slot_cache()->Put(slot_kind, name, feedback_index(slot)); 72801cb0ef41Sopenharmony_ci return slot; 72811cb0ef41Sopenharmony_ci} 72821cb0ef41Sopenharmony_ci 72831cb0ef41Sopenharmony_ciFeedbackSlot BytecodeGenerator::GetCachedStoreICSlot(const Expression* expr, 72841cb0ef41Sopenharmony_ci const AstRawString* name) { 72851cb0ef41Sopenharmony_ci if (!FLAG_ignition_share_named_property_feedback) { 72861cb0ef41Sopenharmony_ci return feedback_spec()->AddStoreICSlot(language_mode()); 72871cb0ef41Sopenharmony_ci } 72881cb0ef41Sopenharmony_ci FeedbackSlotCache::SlotKind slot_kind = 72891cb0ef41Sopenharmony_ci is_strict(language_mode()) ? FeedbackSlotCache::SlotKind::kSetNamedStrict 72901cb0ef41Sopenharmony_ci : FeedbackSlotCache::SlotKind::kSetNamedSloppy; 72911cb0ef41Sopenharmony_ci if (!expr->IsVariableProxy()) { 72921cb0ef41Sopenharmony_ci return feedback_spec()->AddStoreICSlot(language_mode()); 72931cb0ef41Sopenharmony_ci } 72941cb0ef41Sopenharmony_ci const VariableProxy* proxy = expr->AsVariableProxy(); 72951cb0ef41Sopenharmony_ci FeedbackSlot slot( 72961cb0ef41Sopenharmony_ci feedback_slot_cache()->Get(slot_kind, proxy->var()->index(), name)); 72971cb0ef41Sopenharmony_ci if (!slot.IsInvalid()) { 72981cb0ef41Sopenharmony_ci return slot; 72991cb0ef41Sopenharmony_ci } 73001cb0ef41Sopenharmony_ci slot = feedback_spec()->AddStoreICSlot(language_mode()); 73011cb0ef41Sopenharmony_ci feedback_slot_cache()->Put(slot_kind, proxy->var()->index(), name, 73021cb0ef41Sopenharmony_ci feedback_index(slot)); 73031cb0ef41Sopenharmony_ci return slot; 73041cb0ef41Sopenharmony_ci} 73051cb0ef41Sopenharmony_ci 73061cb0ef41Sopenharmony_ciint BytecodeGenerator::GetCachedCreateClosureSlot(FunctionLiteral* literal) { 73071cb0ef41Sopenharmony_ci FeedbackSlotCache::SlotKind slot_kind = 73081cb0ef41Sopenharmony_ci FeedbackSlotCache::SlotKind::kClosureFeedbackCell; 73091cb0ef41Sopenharmony_ci int index = feedback_slot_cache()->Get(slot_kind, literal); 73101cb0ef41Sopenharmony_ci if (index != -1) { 73111cb0ef41Sopenharmony_ci return index; 73121cb0ef41Sopenharmony_ci } 73131cb0ef41Sopenharmony_ci index = feedback_spec()->AddCreateClosureSlot(); 73141cb0ef41Sopenharmony_ci feedback_slot_cache()->Put(slot_kind, literal, index); 73151cb0ef41Sopenharmony_ci return index; 73161cb0ef41Sopenharmony_ci} 73171cb0ef41Sopenharmony_ci 73181cb0ef41Sopenharmony_ciFeedbackSlot BytecodeGenerator::GetDummyCompareICSlot() { 73191cb0ef41Sopenharmony_ci return dummy_feedback_slot_.Get(); 73201cb0ef41Sopenharmony_ci} 73211cb0ef41Sopenharmony_ci 73221cb0ef41Sopenharmony_ci} // namespace interpreter 73231cb0ef41Sopenharmony_ci} // namespace internal 73241cb0ef41Sopenharmony_ci} // namespace v8 7325