[Interpreter] Add support for local context loads and stores.
Adds support for local context loads and stores. Also adds support for creation of new block contexts (e.g., for let variables) and initializing const / let variables with the hole appropriately. Also adds some checks to ensure BytecodeArrayBuilder::context_count is set appropriately and fixes tests to do so. Adds the bytecode StaContextSlot. BUG=v8:4280 LOG=N Review URL: https://codereview.chromium.org/1403943004 Cr-Commit-Position: refs/heads/master@{#31343}
This commit is contained in:
parent
4b2fffae4c
commit
2c8340dac4
src
compiler
interpreter
test
cctest/interpreter
unittests
@ -273,6 +273,12 @@ void BytecodeGraphBuilder::VisitLdaContextSlot(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitStaContextSlot(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitLoadICSloppy(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
UNIMPLEMENTED();
|
||||
|
@ -305,6 +305,15 @@ Node* InterpreterAssembler::LoadContextSlot(Node* context, Node* slot_index) {
|
||||
}
|
||||
|
||||
|
||||
Node* InterpreterAssembler::StoreContextSlot(Node* context, Node* slot_index,
|
||||
Node* value) {
|
||||
Node* offset =
|
||||
IntPtrAdd(WordShl(slot_index, kPointerSizeLog2),
|
||||
Int32Constant(Context::kHeaderSize - kHeapObjectTag));
|
||||
return raw_assembler_->Store(kMachAnyTagged, context, offset, value);
|
||||
}
|
||||
|
||||
|
||||
Node* InterpreterAssembler::LoadTypeFeedbackVector() {
|
||||
Node* function = raw_assembler_->Load(
|
||||
kMachAnyTagged, RegisterFileRawPointer(),
|
||||
|
@ -97,6 +97,8 @@ class InterpreterAssembler {
|
||||
|
||||
// Load |slot_index| from |context|.
|
||||
Node* LoadContextSlot(Node* context, Node* slot_index);
|
||||
// Stores |value| into |slot_index| of |context|.
|
||||
Node* StoreContextSlot(Node* context, Node* slot_index, Node* value);
|
||||
|
||||
// Load the TypeFeedbackVector for the current function.
|
||||
Node* LoadTypeFeedbackVector();
|
||||
|
@ -32,17 +32,11 @@ void BytecodeArrayBuilder::set_locals_count(int number_of_locals) {
|
||||
}
|
||||
|
||||
|
||||
int BytecodeArrayBuilder::locals_count() const { return local_register_count_; }
|
||||
|
||||
|
||||
void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) {
|
||||
parameter_count_ = number_of_parameters;
|
||||
}
|
||||
|
||||
|
||||
int BytecodeArrayBuilder::parameter_count() const { return parameter_count_; }
|
||||
|
||||
|
||||
void BytecodeArrayBuilder::set_context_count(int number_of_contexts) {
|
||||
context_register_count_ = number_of_contexts;
|
||||
DCHECK_GE(local_register_count_, 0);
|
||||
@ -64,20 +58,17 @@ Register BytecodeArrayBuilder::last_context_register() const {
|
||||
|
||||
Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
|
||||
DCHECK_GE(parameter_index, 0);
|
||||
DCHECK_LT(parameter_index, parameter_count_);
|
||||
return Register::FromParameterIndex(parameter_index, parameter_count_);
|
||||
return Register::FromParameterIndex(parameter_index, parameter_count());
|
||||
}
|
||||
|
||||
|
||||
Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
|
||||
DCHECK_EQ(bytecode_generated_, false);
|
||||
DCHECK_GE(parameter_count_, 0);
|
||||
DCHECK_GE(local_register_count_, 0);
|
||||
|
||||
EnsureReturn();
|
||||
|
||||
int bytecode_size = static_cast<int>(bytecodes_.size());
|
||||
int register_count = local_register_count_ + temporary_register_count_;
|
||||
int register_count = fixed_register_count() + temporary_register_count_;
|
||||
int frame_size = register_count * kPointerSize;
|
||||
|
||||
Factory* factory = isolate_->factory();
|
||||
@ -90,7 +81,7 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
|
||||
|
||||
Handle<BytecodeArray> output =
|
||||
factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size,
|
||||
parameter_count_, constant_pool);
|
||||
parameter_count(), constant_pool);
|
||||
bytecode_generated_ = true;
|
||||
return output;
|
||||
}
|
||||
@ -289,6 +280,19 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
|
||||
}
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
|
||||
int slot_index) {
|
||||
DCHECK(slot_index >= 0);
|
||||
if (FitsInIdx8Operand(slot_index)) {
|
||||
Output(Bytecode::kStaContextSlot, context.ToOperand(),
|
||||
static_cast<uint8_t>(slot_index));
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
|
||||
Register object, int feedback_slot, LanguageMode language_mode) {
|
||||
Bytecode bytecode = BytecodeForLoadIC(language_mode);
|
||||
@ -638,9 +642,8 @@ size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
|
||||
|
||||
|
||||
int BytecodeArrayBuilder::BorrowTemporaryRegister() {
|
||||
DCHECK_GE(local_register_count_, 0);
|
||||
int temporary_reg_index = temporary_register_next_++;
|
||||
int count = temporary_register_next_ - local_register_count_;
|
||||
int count = temporary_register_next_ - fixed_register_count();
|
||||
if (count > temporary_register_count_) {
|
||||
temporary_register_count_ = count;
|
||||
}
|
||||
@ -671,8 +674,8 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
|
||||
if (reg.is_function_context() || reg.is_function_closure()) {
|
||||
return true;
|
||||
} else if (reg.is_parameter()) {
|
||||
int parameter_index = reg.ToParameterIndex(parameter_count_);
|
||||
return parameter_index >= 0 && parameter_index < parameter_count_;
|
||||
int parameter_index = reg.ToParameterIndex(parameter_count());
|
||||
return parameter_index >= 0 && parameter_index < parameter_count();
|
||||
} else {
|
||||
return (reg.index() >= 0 && reg.index() < temporary_register_next_);
|
||||
}
|
||||
|
@ -30,19 +30,31 @@ class BytecodeArrayBuilder {
|
||||
|
||||
// Set number of parameters expected by function.
|
||||
void set_parameter_count(int number_of_params);
|
||||
int parameter_count() const;
|
||||
int parameter_count() const {
|
||||
DCHECK_GE(parameter_count_, 0);
|
||||
return parameter_count_;
|
||||
}
|
||||
|
||||
// Set number of locals required for bytecode array.
|
||||
void set_locals_count(int number_of_locals);
|
||||
int locals_count() const;
|
||||
int locals_count() const {
|
||||
DCHECK_GE(local_register_count_, 0);
|
||||
return local_register_count_;
|
||||
}
|
||||
|
||||
// Set number of contexts required for bytecode array.
|
||||
void set_context_count(int number_of_contexts);
|
||||
int context_count() const;
|
||||
int context_count() const {
|
||||
DCHECK_GE(context_register_count_, 0);
|
||||
return context_register_count_;
|
||||
}
|
||||
|
||||
Register first_context_register() const;
|
||||
Register last_context_register() const;
|
||||
|
||||
// Returns the number of fixed (non-temporary) registers.
|
||||
int fixed_register_count() const { return context_count() + locals_count(); }
|
||||
|
||||
Register Parameter(int parameter_index) const;
|
||||
|
||||
// Constant loads to the accumulator.
|
||||
@ -61,6 +73,9 @@ class BytecodeArrayBuilder {
|
||||
// Load the object at |slot_index| in |context| into the accumulator.
|
||||
BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index);
|
||||
|
||||
// Stores the object in the accumulator into |slot_index| of |context|.
|
||||
BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index);
|
||||
|
||||
// Register-accumulator transfers.
|
||||
BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
|
||||
BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
|
||||
|
@ -23,39 +23,54 @@ namespace interpreter {
|
||||
// popping of the current {context_register} during visitation.
|
||||
class BytecodeGenerator::ContextScope BASE_EMBEDDED {
|
||||
public:
|
||||
explicit ContextScope(BytecodeGenerator* generator,
|
||||
bool is_function_context = false)
|
||||
ContextScope(BytecodeGenerator* generator, Scope* scope,
|
||||
bool should_pop_context = true)
|
||||
: generator_(generator),
|
||||
outer_(generator_->current_context()),
|
||||
is_function_context_(is_function_context) {
|
||||
DCHECK(!is_function_context ||
|
||||
outer_.index() == Register::function_context().index());
|
||||
Register new_context_reg = NewContextRegister();
|
||||
generator_->builder()->PushContext(new_context_reg);
|
||||
generator_->set_current_context(new_context_reg);
|
||||
scope_(scope),
|
||||
outer_(generator_->execution_context()),
|
||||
register_(generator_->NextContextRegister()),
|
||||
depth_(0),
|
||||
should_pop_context_(should_pop_context) {
|
||||
if (outer_) {
|
||||
depth_ = outer_->depth_ + 1;
|
||||
generator_->builder()->PushContext(register_);
|
||||
}
|
||||
generator_->set_execution_context(this);
|
||||
}
|
||||
|
||||
~ContextScope() {
|
||||
if (!is_function_context_) {
|
||||
generator_->builder()->PopContext(outer_);
|
||||
if (outer_ && should_pop_context_) {
|
||||
generator_->builder()->PopContext(outer_->reg());
|
||||
}
|
||||
generator_->set_current_context(outer_);
|
||||
generator_->set_execution_context(outer_);
|
||||
}
|
||||
|
||||
// Returns the execution context for the given |scope| if it is a function
|
||||
// local execution context, otherwise returns nullptr.
|
||||
ContextScope* Previous(Scope* scope) {
|
||||
int depth = scope_->ContextChainLength(scope);
|
||||
if (depth > depth_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ContextScope* previous = this;
|
||||
for (int i = depth; i > 0; --i) {
|
||||
previous = previous->outer_;
|
||||
}
|
||||
DCHECK_EQ(previous->scope_, scope);
|
||||
return previous;
|
||||
}
|
||||
|
||||
Scope* scope() const { return scope_; }
|
||||
Register reg() const { return register_; }
|
||||
|
||||
private:
|
||||
Register NewContextRegister() const {
|
||||
if (outer_.index() == Register::function_context().index()) {
|
||||
return generator_->builder()->first_context_register();
|
||||
} else {
|
||||
DCHECK_LT(outer_.index(),
|
||||
generator_->builder()->last_context_register().index());
|
||||
return Register(outer_.index() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
BytecodeGenerator* generator_;
|
||||
Register outer_;
|
||||
bool is_function_context_;
|
||||
Scope* scope_;
|
||||
ContextScope* outer_;
|
||||
Register register_;
|
||||
int depth_;
|
||||
bool should_pop_context_;
|
||||
};
|
||||
|
||||
|
||||
@ -64,10 +79,10 @@ class BytecodeGenerator::ContextScope BASE_EMBEDDED {
|
||||
class BytecodeGenerator::ControlScope BASE_EMBEDDED {
|
||||
public:
|
||||
explicit ControlScope(BytecodeGenerator* generator)
|
||||
: generator_(generator), outer_(generator->control_scope()) {
|
||||
generator_->set_control_scope(this);
|
||||
: generator_(generator), outer_(generator->execution_control()) {
|
||||
generator_->set_execution_control(this);
|
||||
}
|
||||
virtual ~ControlScope() { generator_->set_control_scope(outer()); }
|
||||
virtual ~ControlScope() { generator_->set_execution_control(outer()); }
|
||||
|
||||
void Break(Statement* stmt) { PerformCommand(CMD_BREAK, stmt); }
|
||||
void Continue(Statement* stmt) { PerformCommand(CMD_CONTINUE, stmt); }
|
||||
@ -138,8 +153,8 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
|
||||
info_(nullptr),
|
||||
scope_(nullptr),
|
||||
globals_(0, zone),
|
||||
control_scope_(nullptr),
|
||||
current_context_(Register::function_context()) {
|
||||
execution_control_(nullptr),
|
||||
execution_context_(nullptr) {
|
||||
InitializeAstVisitor(isolate);
|
||||
}
|
||||
|
||||
@ -151,6 +166,9 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
|
||||
set_info(info);
|
||||
set_scope(info->scope());
|
||||
|
||||
// Initialize the incoming context.
|
||||
ContextScope incoming_context(this, scope(), false);
|
||||
|
||||
builder()->set_parameter_count(info->num_parameters_including_this());
|
||||
builder()->set_locals_count(scope()->num_stack_slots());
|
||||
builder()->set_context_count(scope()->MaxNestedContextChainLength());
|
||||
@ -159,7 +177,8 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
|
||||
if (scope()->NeedsContext()) {
|
||||
// Push a new inner context scope for the function.
|
||||
VisitNewLocalFunctionContext();
|
||||
ContextScope top_context(this, true);
|
||||
ContextScope local_function_context(this, scope(), false);
|
||||
VisitBuildLocalActivationContext();
|
||||
MakeBytecodeBody();
|
||||
} else {
|
||||
MakeBytecodeBody();
|
||||
@ -180,18 +199,21 @@ void BytecodeGenerator::MakeBytecodeBody() {
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitBlock(Block* node) {
|
||||
void BytecodeGenerator::VisitBlock(Block* stmt) {
|
||||
builder()->EnterBlock();
|
||||
if (node->scope() == NULL) {
|
||||
if (stmt->scope() == NULL) {
|
||||
// Visit statements in the same scope, no declarations.
|
||||
VisitStatements(node->statements());
|
||||
VisitStatements(stmt->statements());
|
||||
} else {
|
||||
// Visit declarations and statements in a block scope.
|
||||
if (node->scope()->ContextLocalCount() > 0) {
|
||||
UNIMPLEMENTED();
|
||||
if (stmt->scope()->NeedsContext()) {
|
||||
VisitNewLocalBlockContext(stmt->scope());
|
||||
ContextScope scope(this, stmt->scope());
|
||||
VisitDeclarations(stmt->scope()->declarations());
|
||||
VisitStatements(stmt->statements());
|
||||
} else {
|
||||
VisitDeclarations(node->scope()->declarations());
|
||||
VisitStatements(node->statements());
|
||||
VisitDeclarations(stmt->scope()->declarations());
|
||||
VisitStatements(stmt->statements());
|
||||
}
|
||||
}
|
||||
builder()->LeaveBlock();
|
||||
@ -201,10 +223,9 @@ void BytecodeGenerator::VisitBlock(Block* node) {
|
||||
void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
|
||||
Variable* variable = decl->proxy()->var();
|
||||
VariableMode mode = decl->mode();
|
||||
// Const and let variables are initialized with the hole so that we can
|
||||
// check that they are only assigned once.
|
||||
bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET;
|
||||
if (hole_init) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
switch (variable->location()) {
|
||||
case VariableLocation::GLOBAL:
|
||||
case VariableLocation::UNALLOCATED: {
|
||||
@ -215,11 +236,26 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
|
||||
globals()->push_back(value);
|
||||
break;
|
||||
}
|
||||
case VariableLocation::PARAMETER:
|
||||
case VariableLocation::LOCAL:
|
||||
// Details stored in scope, i.e. variable index.
|
||||
if (hole_init) {
|
||||
Register destination(variable->index());
|
||||
builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
|
||||
}
|
||||
break;
|
||||
case VariableLocation::PARAMETER:
|
||||
if (hole_init) {
|
||||
// The parameter indices are shifted by 1 (receiver is variable
|
||||
// index -1 but is parameter index 0 in BytecodeArrayBuilder).
|
||||
Register destination(builder()->Parameter(variable->index() + 1));
|
||||
builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
|
||||
}
|
||||
break;
|
||||
case VariableLocation::CONTEXT:
|
||||
if (hole_init) {
|
||||
builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(),
|
||||
variable->index());
|
||||
}
|
||||
break;
|
||||
case VariableLocation::LOOKUP:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
@ -326,12 +362,12 @@ void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
|
||||
control_scope()->Continue(stmt->target());
|
||||
execution_control()->Continue(stmt->target());
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
|
||||
control_scope()->Break(stmt->target());
|
||||
execution_control()->Break(stmt->target());
|
||||
}
|
||||
|
||||
|
||||
@ -356,7 +392,7 @@ void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); }
|
||||
|
||||
void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
||||
LoopBuilder loop_builder(builder());
|
||||
ControlScopeForIteration control_scope(this, stmt, &loop_builder);
|
||||
ControlScopeForIteration execution_control(this, stmt, &loop_builder);
|
||||
|
||||
BytecodeLabel body_label, condition_label, done_label;
|
||||
builder()->Bind(&body_label);
|
||||
@ -373,7 +409,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
||||
|
||||
void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
|
||||
LoopBuilder loop_builder(builder());
|
||||
ControlScopeForIteration control_scope(this, stmt, &loop_builder);
|
||||
ControlScopeForIteration execution_control(this, stmt, &loop_builder);
|
||||
|
||||
BytecodeLabel body_label, condition_label, done_label;
|
||||
builder()->Jump(&condition_label);
|
||||
@ -391,7 +427,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
|
||||
|
||||
void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
|
||||
LoopBuilder loop_builder(builder());
|
||||
ControlScopeForIteration control_scope(this, stmt, &loop_builder);
|
||||
ControlScopeForIteration execution_control(this, stmt, &loop_builder);
|
||||
|
||||
if (stmt->init() != nullptr) {
|
||||
Visit(stmt->init());
|
||||
@ -595,8 +631,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
}
|
||||
}
|
||||
|
||||
// Create nodes to define accessors, using only a single call to the runtime
|
||||
// for each pair of corresponding getters and setters.
|
||||
// Define accessors, using only a single call to the runtime for each pair of
|
||||
// corresponding getters and setters.
|
||||
for (AccessorTable::Iterator it = accessor_table.begin();
|
||||
it != accessor_table.end(); ++it) {
|
||||
TemporaryRegisterScope inner_temporary_register_scope(builder());
|
||||
@ -698,8 +734,8 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
TemporaryRegisterScope temporary_register_scope(builder());
|
||||
Register index, literal;
|
||||
|
||||
// Create nodes to evaluate all the non-constant subexpressions and to store
|
||||
// them into the newly cloned array.
|
||||
// Evaluate all the non-constant subexpressions and store them into the
|
||||
// newly cloned array.
|
||||
bool literal_in_accumulator = true;
|
||||
for (int array_index = 0; array_index < expr->values()->length();
|
||||
array_index++) {
|
||||
@ -744,6 +780,8 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
|
||||
case VariableLocation::LOCAL: {
|
||||
Register source(variable->index());
|
||||
builder()->LoadAccumulatorWithRegister(source);
|
||||
// TODO(rmcilroy): Perform check for uninitialized legacy const, const and
|
||||
// let variables.
|
||||
break;
|
||||
}
|
||||
case VariableLocation::PARAMETER: {
|
||||
@ -765,14 +803,24 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
|
||||
case VariableLocation::UNALLOCATED: {
|
||||
TemporaryRegisterScope temporary_register_scope(builder());
|
||||
Register obj = temporary_register_scope.NewRegister();
|
||||
builder()->LoadContextSlot(current_context(),
|
||||
builder()->LoadContextSlot(execution_context()->reg(),
|
||||
Context::GLOBAL_OBJECT_INDEX);
|
||||
builder()->StoreAccumulatorInRegister(obj);
|
||||
builder()->LoadLiteral(variable->name());
|
||||
builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode());
|
||||
break;
|
||||
}
|
||||
case VariableLocation::CONTEXT:
|
||||
case VariableLocation::CONTEXT: {
|
||||
ContextScope* context = execution_context()->Previous(variable->scope());
|
||||
if (context) {
|
||||
builder()->LoadContextSlot(context->reg(), variable->index());
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
// TODO(rmcilroy): Perform check for uninitialized legacy const, const and
|
||||
// let variables.
|
||||
break;
|
||||
}
|
||||
case VariableLocation::LOOKUP:
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
@ -812,7 +860,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
|
||||
// TODO(rmcilroy): Investigate whether we can avoid having to stash the
|
||||
// value in a register.
|
||||
builder()->StoreAccumulatorInRegister(value);
|
||||
builder()->LoadContextSlot(current_context(),
|
||||
builder()->LoadContextSlot(execution_context()->reg(),
|
||||
Context::GLOBAL_OBJECT_INDEX);
|
||||
builder()->StoreAccumulatorInRegister(obj);
|
||||
builder()->LoadLiteral(variable->name());
|
||||
@ -822,7 +870,16 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
|
||||
language_mode());
|
||||
break;
|
||||
}
|
||||
case VariableLocation::CONTEXT:
|
||||
case VariableLocation::CONTEXT: {
|
||||
// TODO(rmcilroy): support const mode initialization.
|
||||
ContextScope* context = execution_context()->Previous(variable->scope());
|
||||
if (context) {
|
||||
builder()->StoreContextSlot(context->reg(), variable->index());
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VariableLocation::LOOKUP:
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
@ -1172,6 +1229,11 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() {
|
||||
builder()->CallRuntime(Runtime::kNewFunctionContext,
|
||||
Register::function_closure(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitBuildLocalActivationContext() {
|
||||
Scope* scope = this->scope();
|
||||
|
||||
if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
|
||||
UNIMPLEMENTED();
|
||||
@ -1181,13 +1243,37 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() {
|
||||
int num_parameters = scope->num_parameters();
|
||||
for (int i = 0; i < num_parameters; i++) {
|
||||
Variable* variable = scope->parameter(i);
|
||||
if (variable->IsContextSlot()) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
if (!variable->IsContextSlot()) continue;
|
||||
|
||||
// The parameter indices are shifted by 1 (receiver is variable
|
||||
// index -1 but is parameter index 0 in BytecodeArrayBuilder).
|
||||
Register parameter(builder()->Parameter(i + 1));
|
||||
// Context variable (at bottom of the context chain).
|
||||
DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
|
||||
builder()->LoadAccumulatorWithRegister(parameter)
|
||||
.StoreContextSlot(execution_context()->reg(), variable->index());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) {
|
||||
DCHECK(scope->is_block_scope());
|
||||
|
||||
// Allocate a new local block context.
|
||||
TemporaryRegisterScope temporary_register_scope(builder());
|
||||
Register scope_info = temporary_register_scope.NewRegister();
|
||||
Register closure = temporary_register_scope.NewRegister();
|
||||
DCHECK(Register::AreContiguous(scope_info, closure));
|
||||
builder()
|
||||
->LoadLiteral(scope->GetScopeInfo(isolate()))
|
||||
.StoreAccumulatorInRegister(scope_info);
|
||||
VisitFunctionClosureForContext();
|
||||
builder()
|
||||
->StoreAccumulatorInRegister(closure)
|
||||
.CallRuntime(Runtime::kPushBlockContext, scope_info, 2);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) {
|
||||
Token::Value op = binop->op();
|
||||
Expression* left = binop->left();
|
||||
@ -1203,41 +1289,6 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) {
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitObjectLiteralAccessor(
|
||||
Register home_object, ObjectLiteralProperty* property, Register value_out) {
|
||||
// TODO(rmcilroy): Replace value_out with VisitForRegister();
|
||||
if (property == nullptr) {
|
||||
builder()->LoadNull().StoreAccumulatorInRegister(value_out);
|
||||
} else {
|
||||
Visit(property->value());
|
||||
builder()->StoreAccumulatorInRegister(value_out);
|
||||
VisitSetHomeObject(value_out, home_object, property);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
|
||||
ObjectLiteralProperty* property,
|
||||
int slot_number) {
|
||||
Expression* expr = property->value();
|
||||
if (!FunctionLiteral::NeedsHomeObject(expr)) return;
|
||||
|
||||
// TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the
|
||||
// home object.
|
||||
UNIMPLEMENTED();
|
||||
|
||||
TemporaryRegisterScope temporary_register_scope(builder());
|
||||
Register name = temporary_register_scope.NewRegister();
|
||||
isolate()->factory()->home_object_symbol();
|
||||
builder()
|
||||
->LoadLiteral(isolate()->factory()->home_object_symbol())
|
||||
.StoreAccumulatorInRegister(name)
|
||||
.StoreNamedProperty(home_object, name,
|
||||
feedback_index(property->GetSlot(slot_number)),
|
||||
language_mode());
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
|
||||
Expression* left = binop->left();
|
||||
Expression* right = binop->right();
|
||||
@ -1285,6 +1336,74 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitObjectLiteralAccessor(
|
||||
Register home_object, ObjectLiteralProperty* property, Register value_out) {
|
||||
// TODO(rmcilroy): Replace value_out with VisitForRegister();
|
||||
if (property == nullptr) {
|
||||
builder()->LoadNull().StoreAccumulatorInRegister(value_out);
|
||||
} else {
|
||||
Visit(property->value());
|
||||
builder()->StoreAccumulatorInRegister(value_out);
|
||||
VisitSetHomeObject(value_out, home_object, property);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
|
||||
ObjectLiteralProperty* property,
|
||||
int slot_number) {
|
||||
Expression* expr = property->value();
|
||||
if (!FunctionLiteral::NeedsHomeObject(expr)) return;
|
||||
|
||||
// TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the
|
||||
// home object.
|
||||
UNIMPLEMENTED();
|
||||
|
||||
TemporaryRegisterScope temporary_register_scope(builder());
|
||||
Register name = temporary_register_scope.NewRegister();
|
||||
isolate()->factory()->home_object_symbol();
|
||||
builder()
|
||||
->LoadLiteral(isolate()->factory()->home_object_symbol())
|
||||
.StoreAccumulatorInRegister(name)
|
||||
.StoreNamedProperty(home_object, name,
|
||||
feedback_index(property->GetSlot(slot_number)),
|
||||
language_mode());
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGenerator::VisitFunctionClosureForContext() {
|
||||
Scope* closure_scope = execution_context()->scope()->ClosureScope();
|
||||
if (closure_scope->is_script_scope() ||
|
||||
closure_scope->is_module_scope()) {
|
||||
// Contexts nested in the native context have a canonical empty function as
|
||||
// their closure, not the anonymous closure containing the global code.
|
||||
// Pass a SMI sentinel and let the runtime look up the empty function.
|
||||
builder()->LoadLiteral(Smi::FromInt(0));
|
||||
} else {
|
||||
DCHECK(closure_scope->is_function_scope());
|
||||
builder()->LoadAccumulatorWithRegister(Register::function_closure());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Register BytecodeGenerator::NextContextRegister() const {
|
||||
if (execution_context() == nullptr) {
|
||||
// Return the incoming function context for the outermost execution context.
|
||||
return Register::function_context();
|
||||
}
|
||||
Register previous = execution_context()->reg();
|
||||
if (previous == Register::function_context()) {
|
||||
// If the previous context was the incoming function context, then the next
|
||||
// context register is the first local context register.
|
||||
return builder_.first_context_register();
|
||||
} else {
|
||||
// Otherwise use the next local context register.
|
||||
DCHECK_LT(previous.index(), builder_.last_context_register().index());
|
||||
return Register(previous.index() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LanguageMode BytecodeGenerator::language_mode() const {
|
||||
return info()->language_mode();
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ class BytecodeGenerator : public AstVisitor {
|
||||
class ControlScopeForIteration;
|
||||
|
||||
void MakeBytecodeBody();
|
||||
Register NextContextRegister() const;
|
||||
|
||||
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
|
||||
|
||||
@ -46,6 +47,9 @@ class BytecodeGenerator : public AstVisitor {
|
||||
void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot);
|
||||
void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot);
|
||||
void VisitNewLocalFunctionContext();
|
||||
void VisitBuildLocalActivationContext();
|
||||
void VisitNewLocalBlockContext(Scope* scope);
|
||||
void VisitFunctionClosureForContext();
|
||||
void VisitSetHomeObject(Register value, Register home_object,
|
||||
ObjectLiteralProperty* property, int slot_number = 0);
|
||||
void VisitObjectLiteralAccessor(Register home_object,
|
||||
@ -67,11 +71,13 @@ class BytecodeGenerator : public AstVisitor {
|
||||
inline CompilationInfo* info() const { return info_; }
|
||||
inline void set_info(CompilationInfo* info) { info_ = info; }
|
||||
|
||||
inline ControlScope* control_scope() const { return control_scope_; }
|
||||
inline void set_control_scope(ControlScope* scope) { control_scope_ = scope; }
|
||||
inline Register current_context() const { return current_context_; }
|
||||
inline void set_current_context(Register context) {
|
||||
current_context_ = context;
|
||||
inline ControlScope* execution_control() const { return execution_control_; }
|
||||
inline void set_execution_control(ControlScope* scope) {
|
||||
execution_control_ = scope;
|
||||
}
|
||||
inline ContextScope* execution_context() const { return execution_context_; }
|
||||
inline void set_execution_context(ContextScope* context) {
|
||||
execution_context_ = context;
|
||||
}
|
||||
|
||||
ZoneVector<Handle<Object>>* globals() { return &globals_; }
|
||||
@ -85,9 +91,8 @@ class BytecodeGenerator : public AstVisitor {
|
||||
CompilationInfo* info_;
|
||||
Scope* scope_;
|
||||
ZoneVector<Handle<Object>> globals_;
|
||||
ControlScope* control_scope_;
|
||||
|
||||
Register current_context_;
|
||||
ControlScope* execution_control_;
|
||||
ContextScope* execution_context_;
|
||||
};
|
||||
|
||||
} // namespace interpreter
|
||||
|
@ -49,7 +49,10 @@ namespace interpreter {
|
||||
V(StaGlobalStrict, OperandType::kIdx8) \
|
||||
\
|
||||
/* Context operations */ \
|
||||
V(PushContext, OperandType::kReg8) \
|
||||
V(PopContext, OperandType::kReg8) \
|
||||
V(LdaContextSlot, OperandType::kReg8, OperandType::kIdx8) \
|
||||
V(StaContextSlot, OperandType::kReg8, OperandType::kIdx8) \
|
||||
\
|
||||
/* Register-accumulator transfers */ \
|
||||
V(Ldar, OperandType::kReg8) \
|
||||
@ -69,10 +72,6 @@ namespace interpreter {
|
||||
V(KeyedStoreICStrict, OperandType::kReg8, OperandType::kReg8, \
|
||||
OperandType::kIdx8) \
|
||||
\
|
||||
/* Context operations */ \
|
||||
V(PushContext, OperandType::kReg8) \
|
||||
V(PopContext, OperandType::kReg8) \
|
||||
\
|
||||
/* Binary Operators */ \
|
||||
V(Add, OperandType::kReg8) \
|
||||
V(Sub, OperandType::kReg8) \
|
||||
@ -210,6 +209,9 @@ class Register {
|
||||
Register reg4 = Register(),
|
||||
Register reg5 = Register());
|
||||
|
||||
bool operator==(const Register& o) const { return o.index() == index(); }
|
||||
bool operator!=(const Register& o) const { return o.index() != index(); }
|
||||
|
||||
private:
|
||||
static const int kIllegalIndex = kMaxInt;
|
||||
|
||||
|
@ -235,6 +235,19 @@ void Interpreter::DoLdaContextSlot(compiler::InterpreterAssembler* assembler) {
|
||||
}
|
||||
|
||||
|
||||
// StaContextSlot <context> <slot_index>
|
||||
//
|
||||
// Stores the object in the accumulator into |slot_index| of |context|.
|
||||
void Interpreter::DoStaContextSlot(compiler::InterpreterAssembler* assembler) {
|
||||
Node* value = __ GetAccumulator();
|
||||
Node* reg_index = __ BytecodeOperandReg8(0);
|
||||
Node* context = __ LoadRegister(reg_index);
|
||||
Node* slot_index = __ BytecodeOperandIdx8(1);
|
||||
__ StoreContextSlot(context, slot_index, value);
|
||||
__ Dispatch();
|
||||
}
|
||||
|
||||
|
||||
void Interpreter::DoPropertyLoadIC(Callable ic,
|
||||
compiler::InterpreterAssembler* assembler) {
|
||||
Node* code_target = __ HeapConstant(ic.code());
|
||||
|
@ -134,14 +134,12 @@ static void CheckBytecodeArrayEqual(struct ExpectedSnippet<T> expected,
|
||||
CHECK_EQ(actual->frame_size(), expected.frame_size);
|
||||
CHECK_EQ(actual->parameter_count(), expected.parameter_count);
|
||||
CHECK_EQ(actual->length(), expected.bytecode_length);
|
||||
if (expected.constant_count != -1) {
|
||||
if (expected.constant_count == 0) {
|
||||
CHECK_EQ(actual->constant_pool(), CcTest::heap()->empty_fixed_array());
|
||||
} else {
|
||||
CHECK_EQ(actual->constant_pool()->length(), expected.constant_count);
|
||||
for (int i = 0; i < expected.constant_count; i++) {
|
||||
CheckConstant(expected.constants[i], actual->constant_pool()->get(i));
|
||||
}
|
||||
if (expected.constant_count == 0) {
|
||||
CHECK_EQ(actual->constant_pool(), CcTest::heap()->empty_fixed_array());
|
||||
} else {
|
||||
CHECK_EQ(actual->constant_pool()->length(), expected.constant_count);
|
||||
for (int i = 0; i < expected.constant_count; i++) {
|
||||
CheckConstant(expected.constants[i], actual->constant_pool()->get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1504,7 +1502,7 @@ TEST(DeclareGlobals) {
|
||||
InitializedHandleScope handle_scope;
|
||||
BytecodeGeneratorHelper helper;
|
||||
|
||||
ExpectedSnippet<int> snippets[] = {
|
||||
ExpectedSnippet<InstanceType> snippets[] = {
|
||||
{"var a = 1;",
|
||||
5 * kPointerSize,
|
||||
1,
|
||||
@ -1532,7 +1530,10 @@ TEST(DeclareGlobals) {
|
||||
B(LdaUndefined), //
|
||||
B(Return) //
|
||||
},
|
||||
-1},
|
||||
3,
|
||||
{InstanceType::FIXED_ARRAY_TYPE,
|
||||
InstanceType::FIXED_ARRAY_TYPE,
|
||||
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}},
|
||||
{"function f() {}",
|
||||
3 * kPointerSize,
|
||||
1,
|
||||
@ -1552,7 +1553,8 @@ TEST(DeclareGlobals) {
|
||||
B(LdaUndefined), //
|
||||
B(Return) //
|
||||
},
|
||||
-1},
|
||||
2,
|
||||
{InstanceType::FIXED_ARRAY_TYPE, InstanceType::FIXED_ARRAY_TYPE}},
|
||||
{"var a = 1;\na=2;",
|
||||
5 * kPointerSize,
|
||||
1,
|
||||
@ -1583,7 +1585,10 @@ TEST(DeclareGlobals) {
|
||||
B(Ldar), R(0), //
|
||||
B(Return) //
|
||||
},
|
||||
-1},
|
||||
3,
|
||||
{InstanceType::FIXED_ARRAY_TYPE,
|
||||
InstanceType::FIXED_ARRAY_TYPE,
|
||||
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}},
|
||||
{"function f() {}\nf();",
|
||||
4 * kPointerSize,
|
||||
1,
|
||||
@ -1609,7 +1614,8 @@ TEST(DeclareGlobals) {
|
||||
B(Ldar), R(0), //
|
||||
B(Return) //
|
||||
},
|
||||
-1},
|
||||
2,
|
||||
{InstanceType::FIXED_ARRAY_TYPE, InstanceType::FIXED_ARRAY_TYPE}},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < arraysize(snippets); i++) {
|
||||
@ -1778,8 +1784,7 @@ TEST(BasicLoops) {
|
||||
B(Star), R(0), //
|
||||
B(Ldar), R(0), //
|
||||
B(Star), R(1), //
|
||||
B(LdaSmi8), //
|
||||
U8(1), //
|
||||
B(LdaSmi8), U8(1), //
|
||||
B(TestEqual), R(1), //
|
||||
B(JumpIfFalse), U8(4), //
|
||||
B(Jump), U8(14), //
|
||||
@ -2617,7 +2622,7 @@ TEST(TryCatch) {
|
||||
// TODO(rmcilroy): modify tests when we have real try catch support.
|
||||
ExpectedSnippet<int> snippets[] = {
|
||||
{"try { return 1; } catch(e) { return 2; }",
|
||||
0,
|
||||
1 * kPointerSize,
|
||||
1,
|
||||
5,
|
||||
{
|
||||
@ -2659,7 +2664,7 @@ TEST(TryFinally) {
|
||||
},
|
||||
0},
|
||||
{"var a = 1; try { a = 2; } catch(e) { a = 20 } finally { a = 3; }",
|
||||
1 * kPointerSize,
|
||||
2 * kPointerSize,
|
||||
1,
|
||||
14,
|
||||
{
|
||||
@ -2748,6 +2753,211 @@ TEST(CallNew) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ContextVariables) {
|
||||
InitializedHandleScope handle_scope;
|
||||
BytecodeGeneratorHelper helper;
|
||||
|
||||
int closure = Register::function_closure().index();
|
||||
int first_context_slot = Context::MIN_CONTEXT_SLOTS;
|
||||
ExpectedSnippet<InstanceType> snippets[] = {
|
||||
{"var a; return function() { a = 1; };",
|
||||
1 * kPointerSize,
|
||||
1,
|
||||
12,
|
||||
{
|
||||
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
|
||||
R(closure), U8(1), //
|
||||
B(PushContext), R(0), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Return), //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
{"var a = 1; return function() { a = 2; };",
|
||||
1 * kPointerSize,
|
||||
1,
|
||||
17,
|
||||
{
|
||||
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
|
||||
R(closure), U8(1), //
|
||||
B(PushContext), R(0), //
|
||||
B(LdaSmi8), U8(1), //
|
||||
B(StaContextSlot), R(0), U8(first_context_slot), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Return), //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
{"var a = 1; var b = 2; return function() { a = 2; b = 3 };",
|
||||
1 * kPointerSize,
|
||||
1,
|
||||
22,
|
||||
{
|
||||
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
|
||||
R(closure), U8(1), //
|
||||
B(PushContext), R(0), //
|
||||
B(LdaSmi8), U8(1), //
|
||||
B(StaContextSlot), R(0), U8(first_context_slot), //
|
||||
B(LdaSmi8), U8(2), //
|
||||
B(StaContextSlot), R(0), U8(first_context_slot + 1), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Return), //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
{"var a; (function() { a = 2; })(); return a;",
|
||||
3 * kPointerSize,
|
||||
1,
|
||||
24,
|
||||
{
|
||||
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
|
||||
R(closure), U8(1), //
|
||||
B(PushContext), R(0), //
|
||||
B(LdaUndefined), //
|
||||
B(Star), R(2), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Star), R(1), //
|
||||
B(Call), R(1), R(2), U8(0), //
|
||||
B(LdaContextSlot), R(0), U8(first_context_slot), //
|
||||
B(Return), //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
{"'use strict'; let a = 1; { let b = 2; return function() { a + b; }; }",
|
||||
4 * kPointerSize,
|
||||
1,
|
||||
51,
|
||||
{
|
||||
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
|
||||
R(closure), U8(1), //
|
||||
B(PushContext), R(0), //
|
||||
B(LdaTheHole), //
|
||||
B(StaContextSlot), R(0), U8(first_context_slot), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(LdaSmi8), U8(1), //
|
||||
B(StaContextSlot), R(0), U8(first_context_slot), //
|
||||
B(LdaConstant), U8(1), //
|
||||
B(Star), R(2), //
|
||||
B(Ldar), R(closure), //
|
||||
B(Star), R(3), //
|
||||
B(CallRuntime), U16(Runtime::kPushBlockContext), R(2), U8(2), //
|
||||
B(PushContext), R(1), //
|
||||
B(LdaTheHole), //
|
||||
B(StaContextSlot), R(1), U8(first_context_slot), //
|
||||
B(LdaSmi8), U8(2), //
|
||||
B(StaContextSlot), R(1), U8(first_context_slot), //
|
||||
B(LdaConstant), U8(2), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Return), //
|
||||
// TODO(rmcilroy): Dead code after this point due to return in nested
|
||||
// block - investigate eliminating this.
|
||||
B(PopContext), R(0),
|
||||
B(LdaUndefined), //
|
||||
B(Return), //
|
||||
},
|
||||
3,
|
||||
{InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
|
||||
InstanceType::FIXED_ARRAY_TYPE,
|
||||
InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < arraysize(snippets); i++) {
|
||||
Handle<BytecodeArray> bytecode_array =
|
||||
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
|
||||
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ContextParameters) {
|
||||
InitializedHandleScope handle_scope;
|
||||
BytecodeGeneratorHelper helper;
|
||||
|
||||
int closure = Register::function_closure().index();
|
||||
int first_context_slot = Context::MIN_CONTEXT_SLOTS;
|
||||
ExpectedSnippet<InstanceType> snippets[] = {
|
||||
{"function f(arg1) { return function() { arg1 = 2; }; }",
|
||||
1 * kPointerSize,
|
||||
2,
|
||||
17,
|
||||
{
|
||||
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
|
||||
R(closure), U8(1), //
|
||||
B(PushContext), R(0), //
|
||||
B(Ldar), R(helper.kLastParamIndex), //
|
||||
B(StaContextSlot), R(0), U8(first_context_slot), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Return), //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
{"function f(arg1) { var a = function() { arg1 = 2; }; return arg1; }",
|
||||
2 * kPointerSize,
|
||||
2,
|
||||
22,
|
||||
{
|
||||
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
|
||||
R(closure), U8(1), //
|
||||
B(PushContext), R(1), //
|
||||
B(Ldar), R(helper.kLastParamIndex), //
|
||||
B(StaContextSlot), R(1), U8(first_context_slot), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Star), R(0), //
|
||||
B(LdaContextSlot), R(1), U8(first_context_slot), //
|
||||
B(Return), //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
{"function f(a1, a2, a3, a4) { return function() { a1 = a3; }; }",
|
||||
1 * kPointerSize,
|
||||
5,
|
||||
22,
|
||||
{
|
||||
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
|
||||
R(closure), U8(1), //
|
||||
B(PushContext), R(0), //
|
||||
B(Ldar), R(helper.kLastParamIndex - 3), //
|
||||
B(StaContextSlot), R(0), U8(first_context_slot + 1), //
|
||||
B(Ldar), R(helper.kLastParamIndex -1), //
|
||||
B(StaContextSlot), R(0), U8(first_context_slot), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Return), //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
{"function f() { var self = this; return function() { self = 2; }; }",
|
||||
1 * kPointerSize,
|
||||
1,
|
||||
17,
|
||||
{
|
||||
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
|
||||
R(closure), U8(1), //
|
||||
B(PushContext), R(0), //
|
||||
B(Ldar), R(helper.kLastParamIndex), //
|
||||
B(StaContextSlot), R(0), U8(first_context_slot), //
|
||||
B(LdaConstant), U8(0), //
|
||||
B(CreateClosure), U8(0), //
|
||||
B(Return), //
|
||||
},
|
||||
1,
|
||||
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < arraysize(snippets); i++) {
|
||||
Handle<BytecodeArray> bytecode_array =
|
||||
helper.MakeBytecodeForFunction(snippets[i].code_snippet);
|
||||
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -172,6 +172,7 @@ TEST(InterpreterReturn) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
@ -190,6 +191,7 @@ TEST(InterpreterLoadUndefined) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadUndefined().Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
@ -207,6 +209,7 @@ TEST(InterpreterLoadNull) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadNull().Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
@ -225,6 +228,7 @@ TEST(InterpreterLoadTheHole) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadTheHole().Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
@ -242,6 +246,7 @@ TEST(InterpreterLoadTrue) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadTrue().Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
@ -259,6 +264,7 @@ TEST(InterpreterLoadFalse) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadFalse().Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
@ -278,6 +284,7 @@ TEST(InterpreterLoadLiteral) {
|
||||
for (int i = -128; i < 128; i++) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(Smi::FromInt(i)).Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
@ -292,6 +299,7 @@ TEST(InterpreterLoadLiteral) {
|
||||
{
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(Smi::FromInt(0x12345678)).Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
@ -306,6 +314,7 @@ TEST(InterpreterLoadLiteral) {
|
||||
{
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(factory->NewHeapNumber(-2.1e19)).Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
@ -320,6 +329,7 @@ TEST(InterpreterLoadLiteral) {
|
||||
{
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
Handle<i::String> string = factory->NewStringFromAsciiChecked("String");
|
||||
builder.LoadLiteral(string).Return();
|
||||
@ -339,6 +349,7 @@ TEST(InterpreterLoadStoreRegisters) {
|
||||
for (int i = 0; i <= Register::kMaxRegisterIndex; i++) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(i + 1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
Register reg(i);
|
||||
builder.LoadTrue()
|
||||
@ -424,6 +435,7 @@ TEST(InterpreterShiftOpsSmi) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(),
|
||||
handles.main_zone());
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
Register reg(0);
|
||||
int lhs = lhs_inputs[l];
|
||||
@ -458,6 +470,7 @@ TEST(InterpreterBinaryOpsSmi) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(),
|
||||
handles.main_zone());
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
Register reg(0);
|
||||
int lhs = lhs_inputs[l];
|
||||
@ -493,6 +506,7 @@ TEST(InterpreterBinaryOpsHeapNumber) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(),
|
||||
handles.main_zone());
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
Register reg(0);
|
||||
double lhs = lhs_inputs[l];
|
||||
@ -551,6 +565,7 @@ TEST(InterpreterStringAdd) {
|
||||
for (size_t i = 0; i < arraysize(test_cases); i++) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
Register reg(0);
|
||||
builder.LoadLiteral(test_cases[i].lhs)
|
||||
@ -572,6 +587,7 @@ TEST(InterpreterParameter1) {
|
||||
HandleAndZoneScope handles;
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
@ -595,6 +611,7 @@ TEST(InterpreterParameter8) {
|
||||
HandleAndZoneScope handles;
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(8);
|
||||
builder.LoadAccumulatorWithRegister(builder.Parameter(0))
|
||||
.BinaryOperation(Token::Value::ADD, builder.Parameter(1), Strength::WEAK)
|
||||
@ -631,6 +648,7 @@ TEST(InterpreterParameter1Assign) {
|
||||
HandleAndZoneScope handles;
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(Smi::FromInt(5))
|
||||
.StoreAccumulatorInRegister(builder.Parameter(0))
|
||||
@ -760,6 +778,7 @@ TEST(InterpreterLoadNamedProperty) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(name)
|
||||
.LoadNamedProperty(builder.Parameter(0), vector->GetIndex(slot),
|
||||
@ -816,6 +835,7 @@ TEST(InterpreterLoadKeyedProperty) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(key)
|
||||
.LoadKeyedProperty(builder.Parameter(0), vector->GetIndex(slot),
|
||||
@ -860,6 +880,7 @@ TEST(InterpreterStoreNamedProperty) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(name)
|
||||
.StoreAccumulatorInRegister(Register(0))
|
||||
@ -922,6 +943,7 @@ TEST(InterpreterStoreKeyedProperty) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(name)
|
||||
.StoreAccumulatorInRegister(Register(0))
|
||||
@ -974,6 +996,7 @@ TEST(InterpreterCall) {
|
||||
{
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(name)
|
||||
.LoadNamedProperty(builder.Parameter(0), slot_index, i::SLOPPY)
|
||||
@ -995,6 +1018,7 @@ TEST(InterpreterCall) {
|
||||
{
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(name)
|
||||
.LoadNamedProperty(builder.Parameter(0), slot_index, i::SLOPPY)
|
||||
@ -1019,6 +1043,7 @@ TEST(InterpreterCall) {
|
||||
{
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(4);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(name)
|
||||
.LoadNamedProperty(builder.Parameter(0), slot_index, i::SLOPPY)
|
||||
@ -1048,6 +1073,7 @@ TEST(InterpreterCall) {
|
||||
{
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(12);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(name)
|
||||
.LoadNamedProperty(builder.Parameter(0), slot_index, i::SLOPPY)
|
||||
@ -1121,6 +1147,7 @@ TEST(InterpreterJumps) {
|
||||
HandleAndZoneScope handles;
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(2);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
Register reg(0), scratch(1);
|
||||
BytecodeLabel label[3];
|
||||
@ -1149,6 +1176,7 @@ TEST(InterpreterConditionalJumps) {
|
||||
HandleAndZoneScope handles;
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(2);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
Register reg(0), scratch(1);
|
||||
BytecodeLabel label[2];
|
||||
@ -1237,6 +1265,7 @@ TEST(InterpreterSmiComparisons) {
|
||||
handles.main_zone());
|
||||
Register r0(0);
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
builder.LoadLiteral(Smi::FromInt(inputs[i]))
|
||||
.StoreAccumulatorInRegister(r0)
|
||||
@ -1275,6 +1304,7 @@ TEST(InterpreterHeapNumberComparisons) {
|
||||
handles.main_zone());
|
||||
Register r0(0);
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
builder.LoadLiteral(factory->NewHeapNumber(inputs[i]))
|
||||
.StoreAccumulatorInRegister(r0)
|
||||
@ -1310,6 +1340,7 @@ TEST(InterpreterStringComparisons) {
|
||||
handles.main_zone());
|
||||
Register r0(0);
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs))
|
||||
.StoreAccumulatorInRegister(r0)
|
||||
@ -1356,6 +1387,7 @@ TEST(InterpreterMixedComparisons) {
|
||||
handles.main_zone());
|
||||
Register r0(0);
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
if (pass == 0) {
|
||||
// Comparison with HeapNumber on the lhs and String on the rhs
|
||||
@ -1400,6 +1432,7 @@ TEST(InterpreterInstanceOf) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
Register r0(0);
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
builder.LoadLiteral(cases[i]);
|
||||
builder.StoreAccumulatorInRegister(r0)
|
||||
@ -1430,6 +1463,7 @@ TEST(InterpreterTestIn) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
Register r0(0);
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
builder.LoadLiteral(factory->NewStringFromAsciiChecked(properties[i]))
|
||||
.StoreAccumulatorInRegister(r0)
|
||||
@ -1454,6 +1488,7 @@ TEST(InterpreterUnaryNot) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
Register r0(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
builder.EnterBlock();
|
||||
builder.LoadFalse();
|
||||
@ -1517,6 +1552,7 @@ TEST(InterpreterToBoolean) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
Register r0(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
builder.EnterBlock();
|
||||
LoadAny(&builder, factory, object_type_tuples[i].first);
|
||||
@ -1554,6 +1590,7 @@ TEST(InterpreterUnaryNotNonBoolean) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
Register r0(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
builder.EnterBlock();
|
||||
LoadAny(&builder, factory, object_type_tuples[i].first);
|
||||
@ -1589,6 +1626,7 @@ TEST(InterpreterTypeOf) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
Register r0(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
builder.EnterBlock();
|
||||
LoadAny(&builder, factory, object_type_tuples[i].first);
|
||||
@ -1610,6 +1648,7 @@ TEST(InterpreterCallRuntime) {
|
||||
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(2);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(1);
|
||||
builder.LoadLiteral(Smi::FromInt(15))
|
||||
.StoreAccumulatorInRegister(Register(0))
|
||||
@ -1787,6 +1826,67 @@ TEST(InterpreterConstructWithArguments) {
|
||||
}
|
||||
|
||||
|
||||
TEST(InterpreterContextVariables) {
|
||||
HandleAndZoneScope handles;
|
||||
i::Isolate* isolate = handles.main_isolate();
|
||||
|
||||
std::pair<const char*, Handle<Object>> context_vars[5] = {
|
||||
std::make_pair("var a; (function() { a = 1; })(); return a;",
|
||||
Handle<Object>(Smi::FromInt(1), isolate)),
|
||||
std::make_pair("var a = 10; (function() { a; })(); return a;",
|
||||
Handle<Object>(Smi::FromInt(10), isolate)),
|
||||
std::make_pair("var a = 20; var b = 30;\n"
|
||||
"return (function() { return a + b; })();",
|
||||
Handle<Object>(Smi::FromInt(50), isolate)),
|
||||
std::make_pair("'use strict'; let a = 1;\n"
|
||||
"{ let b = 2; return (function() { return a + b; })(); }",
|
||||
Handle<Object>(Smi::FromInt(3), isolate)),
|
||||
std::make_pair("'use strict'; let a = 10;\n"
|
||||
"{ let b = 20; var c = function() { [a, b] };\n"
|
||||
" return a + b; }",
|
||||
Handle<Object>(Smi::FromInt(30), isolate)),
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < arraysize(context_vars); i++) {
|
||||
std::string source(InterpreterTester::SourceForBody(context_vars[i].first));
|
||||
InterpreterTester tester(handles.main_isolate(), source.c_str());
|
||||
auto callable = tester.GetCallable<>();
|
||||
|
||||
Handle<i::Object> return_value = callable().ToHandleChecked();
|
||||
CHECK(return_value->SameValue(*context_vars[i].second));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InterpreterContextParameters) {
|
||||
HandleAndZoneScope handles;
|
||||
i::Isolate* isolate = handles.main_isolate();
|
||||
|
||||
std::pair<const char*, Handle<Object>> context_params[3] = {
|
||||
std::make_pair("return (function() { return arg1; })();",
|
||||
Handle<Object>(Smi::FromInt(1), isolate)),
|
||||
std::make_pair("(function() { arg1 = 4; })(); return arg1;",
|
||||
Handle<Object>(Smi::FromInt(4), isolate)),
|
||||
std::make_pair("(function() { arg3 = arg2 - arg1; })(); return arg3;",
|
||||
Handle<Object>(Smi::FromInt(1), isolate)),
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < arraysize(context_params); i++) {
|
||||
std::string source = "function " + InterpreterTester::function_name() +
|
||||
"(arg1, arg2, arg3) {" + context_params[i].first + "}";
|
||||
InterpreterTester tester(handles.main_isolate(), source.c_str());
|
||||
auto callable =
|
||||
tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
|
||||
|
||||
Handle<Object> a1 = Handle<Object>(Smi::FromInt(1), isolate);
|
||||
Handle<Object> a2 = Handle<Object>(Smi::FromInt(2), isolate);
|
||||
Handle<Object> a3 = Handle<Object>(Smi::FromInt(3), isolate);
|
||||
Handle<i::Object> return_value = callable(a1, a2, a3).ToHandleChecked();
|
||||
CHECK(return_value->SameValue(*context_params[i].second));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InterpreterComma) {
|
||||
HandleAndZoneScope handles;
|
||||
i::Isolate* isolate = handles.main_isolate();
|
||||
|
@ -98,6 +98,7 @@ Matcher<Node*> BytecodeGraphBuilderTest::IsTrueConstant() {
|
||||
|
||||
TEST_F(BytecodeGraphBuilderTest, ReturnUndefined) {
|
||||
array_builder()->set_locals_count(0);
|
||||
array_builder()->set_context_count(0);
|
||||
array_builder()->set_parameter_count(1);
|
||||
array_builder()->LoadUndefined().Return();
|
||||
|
||||
@ -113,6 +114,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnUndefined) {
|
||||
|
||||
TEST_F(BytecodeGraphBuilderTest, ReturnNull) {
|
||||
array_builder()->set_locals_count(0);
|
||||
array_builder()->set_context_count(0);
|
||||
array_builder()->set_parameter_count(1);
|
||||
array_builder()->LoadNull().Return();
|
||||
|
||||
@ -126,6 +128,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnNull) {
|
||||
|
||||
TEST_F(BytecodeGraphBuilderTest, ReturnTheHole) {
|
||||
array_builder()->set_locals_count(0);
|
||||
array_builder()->set_context_count(0);
|
||||
array_builder()->set_parameter_count(1);
|
||||
array_builder()->LoadTheHole().Return();
|
||||
|
||||
@ -141,6 +144,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnTheHole) {
|
||||
|
||||
TEST_F(BytecodeGraphBuilderTest, ReturnTrue) {
|
||||
array_builder()->set_locals_count(0);
|
||||
array_builder()->set_context_count(0);
|
||||
array_builder()->set_parameter_count(1);
|
||||
array_builder()->LoadTrue().Return();
|
||||
|
||||
@ -156,6 +160,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnTrue) {
|
||||
|
||||
TEST_F(BytecodeGraphBuilderTest, ReturnFalse) {
|
||||
array_builder()->set_locals_count(0);
|
||||
array_builder()->set_context_count(0);
|
||||
array_builder()->set_parameter_count(1);
|
||||
array_builder()->LoadFalse().Return();
|
||||
|
||||
@ -172,6 +177,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnFalse) {
|
||||
TEST_F(BytecodeGraphBuilderTest, ReturnInt8) {
|
||||
static const int kValue = 3;
|
||||
array_builder()->set_locals_count(0);
|
||||
array_builder()->set_context_count(0);
|
||||
array_builder()->set_parameter_count(1);
|
||||
array_builder()->LoadLiteral(Smi::FromInt(kValue)).Return();
|
||||
|
||||
@ -188,6 +194,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnInt8) {
|
||||
TEST_F(BytecodeGraphBuilderTest, ReturnDouble) {
|
||||
const double kValue = 0.123456789;
|
||||
array_builder()->set_locals_count(0);
|
||||
array_builder()->set_context_count(0);
|
||||
array_builder()->set_parameter_count(1);
|
||||
array_builder()->LoadLiteral(factory()->NewHeapNumber(kValue));
|
||||
array_builder()->Return();
|
||||
@ -204,6 +211,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnDouble) {
|
||||
|
||||
TEST_F(BytecodeGraphBuilderTest, SimpleExpressionWithParameters) {
|
||||
array_builder()->set_locals_count(1);
|
||||
array_builder()->set_context_count(0);
|
||||
array_builder()->set_parameter_count(3);
|
||||
array_builder()
|
||||
->LoadAccumulatorWithRegister(array_builder()->Parameter(1))
|
||||
@ -227,6 +235,7 @@ TEST_F(BytecodeGraphBuilderTest, SimpleExpressionWithRegister) {
|
||||
static const int kLeft = -655371;
|
||||
static const int kRight = +2000000;
|
||||
array_builder()->set_locals_count(1);
|
||||
array_builder()->set_context_count(0);
|
||||
array_builder()->set_parameter_count(1);
|
||||
array_builder()
|
||||
->LoadLiteral(Smi::FromInt(kLeft))
|
||||
|
@ -486,6 +486,24 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) {
|
||||
}
|
||||
|
||||
|
||||
TARGET_TEST_F(InterpreterAssemblerTest, StoreContextSlot) {
|
||||
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
|
||||
InterpreterAssemblerForTest m(this, bytecode);
|
||||
Node* context = m.Int32Constant(1);
|
||||
Node* slot_index = m.Int32Constant(22);
|
||||
Node* value = m.Int32Constant(100);
|
||||
Node* store_context_slot = m.StoreContextSlot(context, slot_index, value);
|
||||
|
||||
Matcher<Node*> offset =
|
||||
IsIntPtrAdd(IsWordShl(slot_index, IsInt32Constant(kPointerSizeLog2)),
|
||||
IsInt32Constant(Context::kHeaderSize - kHeapObjectTag));
|
||||
EXPECT_THAT(store_context_slot,
|
||||
m.IsStore(StoreRepresentation(kMachAnyTagged, kNoWriteBarrier),
|
||||
context, offset, value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) {
|
||||
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
|
||||
InterpreterAssemblerForTest m(this, bytecode);
|
||||
|
@ -23,8 +23,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
|
||||
builder.set_locals_count(1);
|
||||
builder.set_context_count(1);
|
||||
builder.set_parameter_count(0);
|
||||
CHECK_EQ(builder.locals_count(), 1);
|
||||
CHECK_EQ(builder.context_count(), 1);
|
||||
CHECK_EQ(builder.fixed_register_count(), 2);
|
||||
|
||||
// Emit constant loads.
|
||||
builder.LoadLiteral(Smi::FromInt(0))
|
||||
@ -49,6 +52,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
builder.PushContext(reg);
|
||||
builder.PopContext(reg);
|
||||
builder.LoadContextSlot(reg, 1);
|
||||
builder.StoreContextSlot(reg, 1);
|
||||
|
||||
// Emit load / store property operations.
|
||||
builder.LoadNamedProperty(reg, 0, LanguageMode::SLOPPY)
|
||||
@ -134,7 +138,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
|
||||
// Generate BytecodeArray.
|
||||
Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
|
||||
CHECK_EQ(the_array->frame_size(), builder.locals_count() * kPointerSize);
|
||||
CHECK_EQ(the_array->frame_size(),
|
||||
builder.fixed_register_count() * kPointerSize);
|
||||
|
||||
// Build scorecard of bytecodes encountered in the BytecodeArray.
|
||||
std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
|
||||
@ -161,20 +166,23 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
|
||||
TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
|
||||
for (int locals = 0; locals < 5; locals++) {
|
||||
for (int temps = 0; temps < 3; temps++) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(0);
|
||||
builder.set_locals_count(locals);
|
||||
builder.Return();
|
||||
for (int contexts = 0; contexts < 4; contexts++) {
|
||||
for (int temps = 0; temps < 3; temps++) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(0);
|
||||
builder.set_locals_count(locals);
|
||||
builder.set_context_count(contexts);
|
||||
builder.Return();
|
||||
|
||||
TemporaryRegisterScope temporaries(&builder);
|
||||
for (int i = 0; i < temps; i++) {
|
||||
temporaries.NewRegister();
|
||||
TemporaryRegisterScope temporaries(&builder);
|
||||
for (int i = 0; i < temps; i++) {
|
||||
temporaries.NewRegister();
|
||||
}
|
||||
|
||||
Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
|
||||
int total_registers = locals + contexts + temps;
|
||||
CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize);
|
||||
}
|
||||
|
||||
Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
|
||||
int total_registers = locals + temps;
|
||||
CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -184,6 +192,7 @@ TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
builder.Return();
|
||||
|
||||
int first;
|
||||
@ -224,6 +233,7 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(10);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
|
||||
Register param0(builder.Parameter(0));
|
||||
Register param9(builder.Parameter(9));
|
||||
@ -235,6 +245,7 @@ TEST_F(BytecodeArrayBuilderTest, Constants) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
|
||||
Factory* factory = isolate()->factory();
|
||||
Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14);
|
||||
@ -260,6 +271,7 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
|
||||
BytecodeLabel far0, far1, far2;
|
||||
BytecodeLabel near0, near1, near2;
|
||||
@ -328,6 +340,7 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
|
||||
BytecodeLabel label0, label1, label2;
|
||||
builder.Bind(&label0)
|
||||
@ -379,6 +392,7 @@ TEST_F(BytecodeArrayBuilderTest, LabelReuse) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
|
||||
// Labels can only have 1 forward reference, but
|
||||
// can be referred to mulitple times once bound.
|
||||
@ -409,6 +423,7 @@ TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
|
||||
for (int i = 0; i < kRepeats; i++) {
|
||||
BytecodeLabel label;
|
||||
@ -440,6 +455,7 @@ TEST_F(BytecodeArrayBuilderTest, ToBoolean) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(0);
|
||||
builder.set_locals_count(0);
|
||||
builder.set_context_count(0);
|
||||
|
||||
// Check ToBoolean emitted at start of block.
|
||||
builder.EnterBlock().CastAccumulatorToBoolean();
|
||||
|
@ -25,6 +25,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
builder.set_parameter_count(3);
|
||||
builder.set_locals_count(2);
|
||||
builder.set_context_count(0);
|
||||
|
||||
Factory* factory = isolate()->factory();
|
||||
Handle<HeapObject> heap_num_0 = factory->NewHeapNumber(2.718);
|
||||
|
Loading…
Reference in New Issue
Block a user