Commit d8df7468 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Add support for property load operations.

Adds support for property load operations via Load/KeyedLoad ICs. Adds the
following bytecodes:
 - LoadIC
 - KeyedLoadIC
Also adds support to the interpreter assembler for loading the type feedback
vector from the function on the stack, and calling ICs.

BUG=v8:4280
LOG=N

Review URL: https://codereview.chromium.org/1309843007

Cr-Commit-Position: refs/heads/master@{#30543}
parent c29a4061
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "src/compiler/raw-machine-assembler.h" #include "src/compiler/raw-machine-assembler.h"
#include "src/compiler/schedule.h" #include "src/compiler/schedule.h"
#include "src/frames.h" #include "src/frames.h"
#include "src/interface-descriptors.h"
#include "src/interpreter/bytecodes.h" #include "src/interpreter/bytecodes.h"
#include "src/macro-assembler.h" #include "src/macro-assembler.h"
#include "src/zone.h" #include "src/zone.h"
...@@ -223,6 +224,35 @@ Node* InterpreterAssembler::LoadContextSlot(int slot_index) { ...@@ -223,6 +224,35 @@ Node* InterpreterAssembler::LoadContextSlot(int slot_index) {
} }
Node* InterpreterAssembler::LoadTypeFeedbackVector() {
Node* function = raw_assembler_->Load(
kMachAnyTagged, RegisterFileRawPointer(),
IntPtrConstant(InterpreterFrameConstants::kFunctionFromRegisterPointer));
Node* shared_info =
LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset);
Node* vector =
LoadObjectField(shared_info, SharedFunctionInfo::kFeedbackVectorOffset);
return vector;
}
Node* InterpreterAssembler::CallIC(CallInterfaceDescriptor descriptor,
Node* target, Node* arg1, Node* arg2,
Node* arg3, Node* arg4) {
CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
isolate(), zone(), descriptor, 0, CallDescriptor::kNoFlags);
Node** args = zone()->NewArray<Node*>(5);
args[0] = arg1;
args[1] = arg2;
args[2] = arg3;
args[3] = arg4;
args[4] = ContextTaggedPointer();
return raw_assembler_->CallN(call_descriptor, target, args);
}
Node* InterpreterAssembler::CallJSBuiltin(int context_index, Node* receiver, Node* InterpreterAssembler::CallJSBuiltin(int context_index, Node* receiver,
Node** js_args, int js_arg_count) { Node** js_args, int js_arg_count) {
Node* global_object = LoadContextSlot(Context::GLOBAL_OBJECT_INDEX); Node* global_object = LoadContextSlot(Context::GLOBAL_OBJECT_INDEX);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class CallInterfaceDescriptor;
class Isolate; class Isolate;
class Zone; class Zone;
...@@ -76,6 +77,13 @@ class InterpreterAssembler { ...@@ -76,6 +77,13 @@ class InterpreterAssembler {
// Load |slot_index| from the current context. // Load |slot_index| from the current context.
Node* LoadContextSlot(int slot_index); Node* LoadContextSlot(int slot_index);
// Load the TypeFeedbackVector for the current function.
Node* LoadTypeFeedbackVector();
// Call an IC code stub.
Node* CallIC(CallInterfaceDescriptor descriptor, Node* target, Node* arg1,
Node* arg2, Node* arg3, Node* arg4);
// Call JS builtin. // Call JS builtin.
Node* CallJSBuiltin(int context_index, Node* receiver); Node* CallJSBuiltin(int context_index, Node* receiver);
Node* CallJSBuiltin(int context_index, Node* receiver, Node* arg1); Node* CallJSBuiltin(int context_index, Node* receiver, Node* arg1);
......
...@@ -180,6 +180,7 @@ class InterpreterFrameConstants : public AllStatic { ...@@ -180,6 +180,7 @@ class InterpreterFrameConstants : public AllStatic {
// Register file pointer relative. // Register file pointer relative.
static const int kLastParamFromRegisterPointer = static const int kLastParamFromRegisterPointer =
StandardFrameConstants::kFixedFrameSize + kPointerSize; StandardFrameConstants::kFixedFrameSize + kPointerSize;
static const int kFunctionFromRegisterPointer = kPointerSize;
}; };
......
...@@ -91,7 +91,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( ...@@ -91,7 +91,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) { BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) {
size_t entry = GetConstantPoolEntry(object); size_t entry = GetConstantPoolEntry(object);
if (entry <= 255) { if (FitsInByteOperand(entry)) {
Output(Bytecode::kLdaConstant, static_cast<uint8_t>(entry)); Output(Bytecode::kLdaConstant, static_cast<uint8_t>(entry));
} else { } else {
UNIMPLEMENTED(); UNIMPLEMENTED();
...@@ -144,6 +144,38 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( ...@@ -144,6 +144,38 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
Register object, int feedback_slot, LanguageMode language_mode) {
if (is_strong(language_mode)) {
UNIMPLEMENTED();
}
if (FitsInByteOperand(feedback_slot)) {
Output(Bytecode::kLoadIC, object.ToOperand(),
static_cast<uint8_t>(feedback_slot));
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
Register object, int feedback_slot, LanguageMode language_mode) {
if (is_strong(language_mode)) {
UNIMPLEMENTED();
}
if (FitsInByteOperand(feedback_slot)) {
Output(Bytecode::kKeyedLoadIC, object.ToOperand(),
static_cast<uint8_t>(feedback_slot));
} else {
UNIMPLEMENTED();
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Return() { BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
Output(Bytecode::kReturn); Output(Bytecode::kReturn);
return *this; return *this;
...@@ -194,9 +226,8 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, ...@@ -194,9 +226,8 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
case OperandType::kNone: case OperandType::kNone:
return false; return false;
case OperandType::kImm8: case OperandType::kImm8:
return true;
case OperandType::kIdx: case OperandType::kIdx:
return operand_value < constants_.size(); return true;
case OperandType::kReg: { case OperandType::kReg: {
int reg_index = Register::FromOperand(operand_value).index(); int reg_index = Register::FromOperand(operand_value).index();
return (reg_index >= 0 && reg_index < temporary_register_next_) || return (reg_index >= 0 && reg_index < temporary_register_next_) ||
...@@ -267,6 +298,18 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { ...@@ -267,6 +298,18 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) {
} }
// static
bool BytecodeArrayBuilder::FitsInByteOperand(int value) {
return 0 <= value && value <= 255;
}
// static
bool BytecodeArrayBuilder::FitsInByteOperand(size_t value) {
return value <= 255;
}
TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder) TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder)
: builder_(builder), count_(0), last_register_index_(-1) {} : builder_(builder), count_(0), last_register_index_(-1) {}
......
...@@ -51,6 +51,12 @@ class BytecodeArrayBuilder { ...@@ -51,6 +51,12 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg); BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg); BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
// Load properties. The property name should be in the accumulator.
BytecodeArrayBuilder& LoadNamedProperty(Register object, int feedback_slot,
LanguageMode language_mode);
BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot,
LanguageMode language_mode);
// Operators. // Operators.
BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg); BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg);
...@@ -62,6 +68,8 @@ class BytecodeArrayBuilder { ...@@ -62,6 +68,8 @@ class BytecodeArrayBuilder {
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize; -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
static Bytecode BytecodeForBinaryOperation(Token::Value op); static Bytecode BytecodeForBinaryOperation(Token::Value op);
static bool FitsInByteOperand(int value);
static bool FitsInByteOperand(size_t value);
void Output(Bytecode bytecode, uint8_t r0, uint8_t r1, uint8_t r2); void Output(Bytecode bytecode, uint8_t r0, uint8_t r1, uint8_t r2);
void Output(Bytecode bytecode, uint8_t r0, uint8_t r1); void Output(Bytecode bytecode, uint8_t r0, uint8_t r1);
......
...@@ -25,6 +25,7 @@ BytecodeGenerator::~BytecodeGenerator() {} ...@@ -25,6 +25,7 @@ BytecodeGenerator::~BytecodeGenerator() {}
Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
set_info(info);
set_scope(info->scope()); set_scope(info->scope());
// This a temporary guard (oth). // This a temporary guard (oth).
...@@ -45,6 +46,7 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { ...@@ -45,6 +46,7 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
VisitStatements(info->literal()->body()); VisitStatements(info->literal()->body());
set_scope(nullptr); set_scope(nullptr);
set_info(nullptr);
return builder_.ToBytecodeArray(); return builder_.ToBytecodeArray();
} }
...@@ -84,17 +86,17 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { ...@@ -84,17 +86,17 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
} }
void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* node) { void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitImportDeclaration(ImportDeclaration* node) { void BytecodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* node) { void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -104,36 +106,36 @@ void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { ...@@ -104,36 +106,36 @@ void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
} }
void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* node) { void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitIfStatement(IfStatement* node) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitContinueStatement(ContinueStatement* node) { void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitBreakStatement(BreakStatement* node) { void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitReturnStatement(ReturnStatement* node) { void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Visit(node->expression()); Visit(stmt->expression());
builder().Return(); builder().Return();
} }
void BytecodeGenerator::VisitWithStatement(WithStatement* node) { void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* node) { void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -141,63 +143,63 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* node) { ...@@ -141,63 +143,63 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) { void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitWhileStatement(WhileStatement* node) { void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitForStatement(ForStatement* node) { void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitForInStatement(ForInStatement* node) { void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitForOfStatement(ForOfStatement* node) { void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) { void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) { void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitClassLiteral(ClassLiteral* node) { void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitNativeFunctionLiteral( void BytecodeGenerator::VisitNativeFunctionLiteral(
NativeFunctionLiteral* node) { NativeFunctionLiteral* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitConditional(Conditional* node) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitConditional(Conditional* expr) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitLiteral(Literal* expr) { void BytecodeGenerator::VisitLiteral(Literal* expr) {
...@@ -220,17 +222,17 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) { ...@@ -220,17 +222,17 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) {
} }
void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -286,30 +288,59 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -286,30 +288,59 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
} }
void BytecodeGenerator::VisitYield(Yield* node) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitYield(Yield* expr) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitThrow(Throw* node) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitThrow(Throw* expr) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitProperty(Property* node) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitProperty(Property* expr) {
LhsKind property_kind = Property::GetAssignType(expr);
FeedbackVectorICSlot slot = expr->PropertyFeedbackSlot();
switch (property_kind) {
case VARIABLE:
UNREACHABLE();
break;
case NAMED_PROPERTY: {
TemporaryRegisterScope temporary_register_scope(&builder_);
Register obj = temporary_register_scope.NewRegister();
Visit(expr->obj());
builder().StoreAccumulatorInRegister(obj);
builder().LoadLiteral(expr->key()->AsLiteral()->AsPropertyName());
builder().LoadNamedProperty(obj, feedback_index(slot), language_mode());
break;
}
case KEYED_PROPERTY: {
TemporaryRegisterScope temporary_register_scope(&builder_);
Register obj = temporary_register_scope.NewRegister();
Visit(expr->obj());
builder().StoreAccumulatorInRegister(obj);
Visit(expr->key());
builder().LoadKeyedProperty(obj, feedback_index(slot), language_mode());
break;
}
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNIMPLEMENTED();
}
}
void BytecodeGenerator::VisitCall(Call* node) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitCall(Call* expr) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitCallNew(CallNew* node) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitCallNew(CallNew* expr) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitCallRuntime(CallRuntime* node) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* node) { void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitCountOperation(CountOperation* node) { void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -328,31 +359,31 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) { ...@@ -328,31 +359,31 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
} }
void BytecodeGenerator::VisitCompareOperation(CompareOperation* node) { void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitSpread(Spread* node) { UNREACHABLE(); } void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); }
void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* node) { void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
UNREACHABLE(); UNREACHABLE();
} }
void BytecodeGenerator::VisitThisFunction(ThisFunction* node) { void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* node) { void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
void BytecodeGenerator::VisitSuperPropertyReference( void BytecodeGenerator::VisitSuperPropertyReference(
SuperPropertyReference* node) { SuperPropertyReference* expr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
...@@ -371,6 +402,16 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { ...@@ -371,6 +402,16 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) {
builder().BinaryOperation(op, temporary); builder().BinaryOperation(op, temporary);
} }
LanguageMode BytecodeGenerator::language_mode() const {
return info()->language_mode();
}
int BytecodeGenerator::feedback_index(FeedbackVectorICSlot slot) const {
return info()->feedback_vector()->GetIndex(slot);
}
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -31,9 +31,15 @@ class BytecodeGenerator : public AstVisitor { ...@@ -31,9 +31,15 @@ class BytecodeGenerator : public AstVisitor {
inline BytecodeArrayBuilder& builder() { return builder_; } inline BytecodeArrayBuilder& builder() { return builder_; }
inline Scope* scope() const { return scope_; } inline Scope* scope() const { return scope_; }
inline void set_scope(Scope* s) { scope_ = s; } inline void set_scope(Scope* scope) { scope_ = scope; }
inline CompilationInfo* info() const { return info_; }
inline void set_info(CompilationInfo* info) { info_ = info; }
LanguageMode language_mode() const;
int feedback_index(FeedbackVectorICSlot slot) const;
BytecodeArrayBuilder builder_; BytecodeArrayBuilder builder_;
CompilationInfo* info_;
Scope* scope_; Scope* scope_;
}; };
......
...@@ -23,30 +23,34 @@ namespace interpreter { ...@@ -23,30 +23,34 @@ namespace interpreter {
V(Reg) V(Reg)
// The list of bytecodes which are interpreted by the interpreter. // The list of bytecodes which are interpreted by the interpreter.
#define BYTECODE_LIST(V) \ #define BYTECODE_LIST(V) \
\ \
/* Loading the accumulator */ \ /* Loading the accumulator */ \
V(LdaZero, OperandType::kNone) \ V(LdaZero, OperandType::kNone) \
V(LdaSmi8, OperandType::kImm8) \ V(LdaSmi8, OperandType::kImm8) \
V(LdaConstant, OperandType::kIdx) \ V(LdaConstant, OperandType::kIdx) \
V(LdaUndefined, OperandType::kNone) \ V(LdaUndefined, OperandType::kNone) \
V(LdaNull, OperandType::kNone) \ V(LdaNull, OperandType::kNone) \
V(LdaTheHole, OperandType::kNone) \ V(LdaTheHole, OperandType::kNone) \
V(LdaTrue, OperandType::kNone) \ V(LdaTrue, OperandType::kNone) \
V(LdaFalse, OperandType::kNone) \ V(LdaFalse, OperandType::kNone) \
\ \
/* Register-accumulator transfers */ \ /* Register-accumulator transfers */ \
V(Ldar, OperandType::kReg) \ V(Ldar, OperandType::kReg) \
V(Star, OperandType::kReg) \ V(Star, OperandType::kReg) \
\ \
/* Binary Operators */ \ /* LoadIC operations */ \
V(Add, OperandType::kReg) \ V(LoadIC, OperandType::kReg, OperandType::kIdx) \
V(Sub, OperandType::kReg) \ V(KeyedLoadIC, OperandType::kReg, OperandType::kIdx) \
V(Mul, OperandType::kReg) \ \
V(Div, OperandType::kReg) \ /* Binary Operators */ \
V(Mod, OperandType::kReg) \ V(Add, OperandType::kReg) \
\ V(Sub, OperandType::kReg) \
/* Control Flow */ \ V(Mul, OperandType::kReg) \
V(Div, OperandType::kReg) \
V(Mod, OperandType::kReg) \
\
/* Control Flow */ \
V(Return, OperandType::kNone) V(Return, OperandType::kNone)
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/interpreter/interpreter.h" #include "src/interpreter/interpreter.h"
#include "src/code-factory.h"
#include "src/compiler.h" #include "src/compiler.h"
#include "src/compiler/interpreter-assembler.h" #include "src/compiler/interpreter-assembler.h"
#include "src/factory.h" #include "src/factory.h"
...@@ -61,6 +62,7 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) { ...@@ -61,6 +62,7 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) {
Handle<SharedFunctionInfo> shared_info = info->shared_info(); Handle<SharedFunctionInfo> shared_info = info->shared_info();
BytecodeGenerator generator(info->isolate(), info->zone()); BytecodeGenerator generator(info->isolate(), info->zone());
info->EnsureFeedbackVector();
Handle<BytecodeArray> bytecodes = generator.MakeBytecode(info); Handle<BytecodeArray> bytecodes = generator.MakeBytecode(info);
if (FLAG_print_bytecode) { if (FLAG_print_bytecode) {
bytecodes->Print(); bytecodes->Print();
...@@ -73,7 +75,6 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) { ...@@ -73,7 +75,6 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) {
shared_info->set_function_data(*bytecodes); shared_info->set_function_data(*bytecodes);
info->SetCode(info->isolate()->builtins()->InterpreterEntryTrampoline()); info->SetCode(info->isolate()->builtins()->InterpreterEntryTrampoline());
info->EnsureFeedbackVector();
return true; return true;
} }
...@@ -190,6 +191,44 @@ void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) { ...@@ -190,6 +191,44 @@ void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) {
} }
void Interpreter::DoPropertyLoadIC(Callable ic,
compiler::InterpreterAssembler* assembler) {
Node* code_target = __ HeapConstant(ic.code());
Node* reg_index = __ BytecodeOperandReg(0);
Node* object = __ LoadRegister(reg_index);
Node* name = __ GetAccumulator();
Node* raw_slot = __ BytecodeOperandIdx(1);
Node* smi_slot = __ SmiTag(raw_slot);
Node* type_feedback_vector = __ LoadTypeFeedbackVector();
Node* result = __ CallIC(ic.descriptor(), code_target, object, name, smi_slot,
type_feedback_vector);
__ SetAccumulator(result);
__ Dispatch();
}
// LoadIC <object> <slot>
//
// Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name
// in the accumulator.
void Interpreter::DoLoadIC(compiler::InterpreterAssembler* assembler) {
Callable ic = CodeFactory::LoadICInOptimizedCode(isolate_, NOT_INSIDE_TYPEOF,
SLOPPY, UNINITIALIZED);
DoPropertyLoadIC(ic, assembler);
}
// KeyedLoadIC <object> <slot>
//
// Calls the LoadIC at FeedBackVector slot <slot> for <object> and the key
// in the accumulator.
void Interpreter::DoKeyedLoadIC(compiler::InterpreterAssembler* assembler) {
Callable ic =
CodeFactory::KeyedLoadICInOptimizedCode(isolate_, SLOPPY, UNINITIALIZED);
DoPropertyLoadIC(ic, assembler);
}
void Interpreter::DoBinaryOp(int builtin_context_index, void Interpreter::DoBinaryOp(int builtin_context_index,
compiler::InterpreterAssembler* assembler) { compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy): Call ICs which back-patch bytecode with type specialized // TODO(rmcilroy): Call ICs which back-patch bytecode with type specialized
......
...@@ -16,6 +16,7 @@ namespace v8 { ...@@ -16,6 +16,7 @@ namespace v8 {
namespace internal { namespace internal {
class Isolate; class Isolate;
class Callable;
class CompilationInfo; class CompilationInfo;
namespace compiler { namespace compiler {
...@@ -51,6 +52,9 @@ class Interpreter { ...@@ -51,6 +52,9 @@ class Interpreter {
void DoBinaryOp(int builtin_context_index, void DoBinaryOp(int builtin_context_index,
compiler::InterpreterAssembler* assembler); compiler::InterpreterAssembler* assembler);
// Generates code to perform a property load via |ic|.
void DoPropertyLoadIC(Callable ic, compiler::InterpreterAssembler* assembler);
bool IsInterpreterTableInitialized(Handle<FixedArray> handler_table); bool IsInterpreterTableInitialized(Handle<FixedArray> handler_table);
Isolate* isolate_; Isolate* isolate_;
......
...@@ -17,6 +17,9 @@ class BytecodeGeneratorHelper { ...@@ -17,6 +17,9 @@ class BytecodeGeneratorHelper {
public: public:
const char* kFunctionName = "f"; const char* kFunctionName = "f";
const int kLastParamIndex =
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
BytecodeGeneratorHelper() { BytecodeGeneratorHelper() {
i::FLAG_ignition = true; i::FLAG_ignition = true;
i::FLAG_ignition_filter = kFunctionName; i::FLAG_ignition_filter = kFunctionName;
...@@ -24,6 +27,9 @@ class BytecodeGeneratorHelper { ...@@ -24,6 +27,9 @@ class BytecodeGeneratorHelper {
} }
Factory* factory() { return CcTest::i_isolate()->factory(); }
Handle<BytecodeArray> MakeBytecode(const char* script, Handle<BytecodeArray> MakeBytecode(const char* script,
const char* function_name) { const char* function_name) {
CompileRun(script); CompileRun(script);
...@@ -52,11 +58,11 @@ class BytecodeGeneratorHelper { ...@@ -52,11 +58,11 @@ class BytecodeGeneratorHelper {
// Structure for containing expected bytecode snippets. // Structure for containing expected bytecode snippets.
template<typename T> template<typename T>
struct ExpectedSnippet { struct ExpectedSnippet {
const char* body; const char* code_snippet;
int frame_size; int frame_size;
int parameter_count; int parameter_count;
int bytecode_length; int bytecode_length;
const uint8_t bytecode[16]; const uint8_t bytecode[24];
int constant_count; int constant_count;
T constants[16]; T constants[16];
}; };
...@@ -87,7 +93,7 @@ TEST(PrimitiveReturnStatements) { ...@@ -87,7 +93,7 @@ TEST(PrimitiveReturnStatements) {
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) { for (size_t i = 0; i < num_snippets; i++) {
Handle<BytecodeArray> ba = Handle<BytecodeArray> ba =
helper.MakeBytecodeForFunctionBody(snippets[i].body); helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
CHECK_EQ(ba->frame_size(), snippets[i].frame_size); CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count);
CHECK_EQ(ba->length(), snippets[i].bytecode_length); CHECK_EQ(ba->length(), snippets[i].bytecode_length);
...@@ -134,7 +140,7 @@ TEST(PrimitiveExpressions) { ...@@ -134,7 +140,7 @@ TEST(PrimitiveExpressions) {
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) { for (size_t i = 0; i < num_snippets; i++) {
Handle<BytecodeArray> ba = Handle<BytecodeArray> ba =
helper.MakeBytecodeForFunctionBody(snippets[i].body); helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
CHECK_EQ(ba->frame_size(), snippets[i].frame_size); CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count);
CHECK_EQ(ba->length(), snippets[i].bytecode_length); CHECK_EQ(ba->length(), snippets[i].bytecode_length);
...@@ -149,24 +155,23 @@ TEST(Parameters) { ...@@ -149,24 +155,23 @@ TEST(Parameters) {
InitializedHandleScope handle_scope; InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper; BytecodeGeneratorHelper helper;
int last_param_index =
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
ExpectedSnippet<void*> snippets[] = { ExpectedSnippet<void*> snippets[] = {
{"function f() { return this; }", {"function f() { return this; }",
0, 1, 3, {B(Ldar), R(last_param_index), B(Return)}, 0}, 0, 1, 3, {B(Ldar), R(helper.kLastParamIndex), B(Return)}, 0},
{"function f(arg1) { return arg1; }", {"function f(arg1) { return arg1; }",
0, 2, 3, {B(Ldar), R(last_param_index), B(Return)}, 0}, 0, 2, 3, {B(Ldar), R(helper.kLastParamIndex), B(Return)}, 0},
{"function f(arg1) { return this; }", {"function f(arg1) { return this; }",
0, 2, 3, {B(Ldar), R(last_param_index - 1), B(Return)}, 0}, 0, 2, 3, {B(Ldar), R(helper.kLastParamIndex - 1), B(Return)}, 0},
{"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return arg4; }", {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return arg4; }",
0, 8, 3, {B(Ldar), R(last_param_index - 3), B(Return)}, 0}, 0, 8, 3, {B(Ldar), R(helper.kLastParamIndex - 3), B(Return)}, 0},
{"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return this; }", {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return this; }",
0, 8, 3, {B(Ldar), R(last_param_index - 7), B(Return)}, 0} 0, 8, 3, {B(Ldar), R(helper.kLastParamIndex - 7), B(Return)}, 0}
}; };
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) { for (size_t i = 0; i < num_snippets; i++) {
Handle<BytecodeArray> ba = helper.MakeBytecodeForFunction(snippets[i].body); Handle<BytecodeArray> ba =
helper.MakeBytecodeForFunction(snippets[i].code_snippet);
CHECK_EQ(ba->frame_size(), snippets[i].frame_size); CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count);
CHECK_EQ(ba->length(), snippets[i].bytecode_length); CHECK_EQ(ba->length(), snippets[i].bytecode_length);
...@@ -212,7 +217,7 @@ TEST(Constants) { ...@@ -212,7 +217,7 @@ TEST(Constants) {
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) { for (size_t i = 0; i < num_snippets; i++) {
Handle<BytecodeArray> ba = Handle<BytecodeArray> ba =
helper.MakeBytecodeForFunctionBody(snippets[i].body); helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
CHECK_EQ(ba->frame_size(), snippets[i].frame_size); CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count);
CHECK_EQ(ba->length(), snippets[i].bytecode_length); CHECK_EQ(ba->length(), snippets[i].bytecode_length);
...@@ -261,7 +266,7 @@ TEST(Constants) { ...@@ -261,7 +266,7 @@ TEST(Constants) {
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) { for (size_t i = 0; i < num_snippets; i++) {
Handle<BytecodeArray> ba = Handle<BytecodeArray> ba =
helper.MakeBytecodeForFunctionBody(snippets[i].body); helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
CHECK_EQ(ba->frame_size(), snippets[i].frame_size); CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count);
CHECK_EQ(ba->length(), snippets[i].bytecode_length); CHECK_EQ(ba->length(), snippets[i].bytecode_length);
...@@ -308,7 +313,7 @@ TEST(Constants) { ...@@ -308,7 +313,7 @@ TEST(Constants) {
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) { for (size_t i = 0; i < num_snippets; i++) {
Handle<BytecodeArray> ba = Handle<BytecodeArray> ba =
helper.MakeBytecodeForFunctionBody(snippets[i].body); helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
CHECK_EQ(ba->frame_size(), snippets[i].frame_size); CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count); CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count);
CHECK_EQ(ba->length(), snippets[i].bytecode_length); CHECK_EQ(ba->length(), snippets[i].bytecode_length);
...@@ -316,9 +321,8 @@ TEST(Constants) { ...@@ -316,9 +321,8 @@ TEST(Constants) {
ba->length())); ba->length()));
CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count); CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count);
for (int j = 0; j < snippets[i].constant_count; j++) { for (int j = 0; j < snippets[i].constant_count; j++) {
Handle<String> expected = Handle<String> expected = helper.factory()->NewStringFromAsciiChecked(
CcTest::i_isolate()->factory()->NewStringFromAsciiChecked( snippets[i].constants[j]);
snippets[i].constants[j]);
CHECK(String::cast(ba->constant_pool()->get(j))->Equals(*expected)); CHECK(String::cast(ba->constant_pool()->get(j))->Equals(*expected));
} }
} }
...@@ -326,6 +330,94 @@ TEST(Constants) { ...@@ -326,6 +330,94 @@ TEST(Constants) {
} }
TEST(PropertyLoads) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
Code::Kind ic_kinds[] = { i::Code::LOAD_IC, i::Code::LOAD_IC };
FeedbackVectorSpec feedback_spec(0, 1, ic_kinds);
Handle<i::TypeFeedbackVector> vector =
helper.factory()->NewTypeFeedbackVector(&feedback_spec);
ExpectedSnippet<const char*> snippets[] = {
{"function f(a) { return a.name; }\nf({name : \"test\"})",
1 * kPointerSize, 2, 10,
{
B(Ldar), R(helper.kLastParamIndex),
B(Star), R(0),
B(LdaConstant), U8(0),
B(LoadIC), R(0), U8(vector->first_ic_slot_index()),
B(Return)
},
1, { "name" }
},
{"function f(a) { return a[\"key\"]; }\nf({key : \"test\"})",
1 * kPointerSize, 2, 10,
{
B(Ldar), R(helper.kLastParamIndex),
B(Star), R(0),
B(LdaConstant), U8(0),
B(LoadIC), R(0), U8(vector->first_ic_slot_index()),
B(Return)
},
1, { "key" }
},
{"function f(a) { return a[100]; }\nf({100 : \"test\"})",
1 * kPointerSize, 2, 10,
{
B(Ldar), R(helper.kLastParamIndex),
B(Star), R(0),
B(LdaSmi8), U8(100),
B(KeyedLoadIC), R(0), U8(vector->first_ic_slot_index()),
B(Return)
}, 0
},
{"function f(a, b) { return a[b]; }\nf({arg : \"test\"}, \"arg\")",
1 * kPointerSize, 3, 10,
{
B(Ldar), R(helper.kLastParamIndex - 1),
B(Star), R(0),
B(Ldar), R(helper.kLastParamIndex),
B(KeyedLoadIC), R(0), U8(vector->first_ic_slot_index()),
B(Return)
}, 0
},
{"function f(a) { var b = a.name; return a[-124]; }\n"
"f({\"-124\" : \"test\", name : 123 })",
2 * kPointerSize, 2, 21,
{
B(Ldar), R(helper.kLastParamIndex),
B(Star), R(1),
B(LdaConstant), U8(0),
B(LoadIC), R(1), U8(vector->first_ic_slot_index()),
B(Star), R(0),
B(Ldar), R(helper.kLastParamIndex),
B(Star), R(1),
B(LdaSmi8), U8(-124),
B(KeyedLoadIC), R(1), U8(vector->first_ic_slot_index() + 2),
B(Return)
},
1, { "name" }
}
};
size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
for (size_t i = 0; i < num_snippets; i++) {
Handle<BytecodeArray> ba =
helper.MakeBytecode(snippets[i].code_snippet, "f");
CHECK_EQ(ba->frame_size(), snippets[i].frame_size);
CHECK_EQ(ba->parameter_count(), snippets[i].parameter_count);
CHECK_EQ(ba->length(), snippets[i].bytecode_length);
CHECK(!memcmp(ba->GetFirstBytecodeAddress(), snippets[i].bytecode,
ba->length()));
CHECK_EQ(ba->constant_pool()->length(), snippets[i].constant_count);
for (int j = 0; j < snippets[i].constant_count; j++) {
Handle<String> expected = helper.factory()->NewStringFromAsciiChecked(
snippets[i].constants[j]);
CHECK(String::cast(ba->constant_pool()->get(j))->Equals(*expected));
}
}
}
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespance v8 } // namespance v8
...@@ -53,8 +53,12 @@ class InterpreterCallable { ...@@ -53,8 +53,12 @@ class InterpreterCallable {
class InterpreterTester { class InterpreterTester {
public: public:
InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode) InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode,
: isolate_(isolate), bytecode_(bytecode) { MaybeHandle<TypeFeedbackVector> feedback_vector =
MaybeHandle<TypeFeedbackVector>())
: isolate_(isolate),
bytecode_(bytecode),
feedback_vector_(feedback_vector) {
i::FLAG_ignition = true; i::FLAG_ignition = true;
// Ensure handler table is generated. // Ensure handler table is generated.
isolate->interpreter()->Initialize(); isolate->interpreter()->Initialize();
...@@ -66,9 +70,14 @@ class InterpreterTester { ...@@ -66,9 +70,14 @@ class InterpreterTester {
return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>()); return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>());
} }
Handle<Object> NewObject(const char* script) {
return v8::Utils::OpenHandle(*CompileRun(script));
}
private: private:
Isolate* isolate_; Isolate* isolate_;
Handle<BytecodeArray> bytecode_; Handle<BytecodeArray> bytecode_;
MaybeHandle<TypeFeedbackVector> feedback_vector_;
template <class... A> template <class... A>
Handle<JSFunction> GetBytecodeFunction() { Handle<JSFunction> GetBytecodeFunction() {
...@@ -83,6 +92,10 @@ class InterpreterTester { ...@@ -83,6 +92,10 @@ class InterpreterTester {
*v8::Handle<v8::Function>::Cast(CompileRun(function_text.c_str()))); *v8::Handle<v8::Function>::Cast(CompileRun(function_text.c_str())));
function->ReplaceCode(*isolate_->builtins()->InterpreterEntryTrampoline()); function->ReplaceCode(*isolate_->builtins()->InterpreterEntryTrampoline());
function->shared()->set_function_data(*bytecode_); function->shared()->set_function_data(*bytecode_);
if (!feedback_vector_.is_null()) {
function->shared()->set_feedback_vector(
*feedback_vector_.ToHandleChecked());
}
return function; return function;
} }
...@@ -400,7 +413,7 @@ TEST(InterpreterMod) { ...@@ -400,7 +413,7 @@ TEST(InterpreterMod) {
TEST(InterpreterParameter1) { TEST(InterpreterParameter1) {
HandleAndZoneScope handles; HandleAndZoneScope handles;
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(1); builder.set_locals_count(0);
builder.set_parameter_count(1); builder.set_parameter_count(1);
builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return(); builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
...@@ -423,7 +436,7 @@ TEST(InterpreterParameter1) { ...@@ -423,7 +436,7 @@ TEST(InterpreterParameter1) {
TEST(InterpreterParameter8) { TEST(InterpreterParameter8) {
HandleAndZoneScope handles; HandleAndZoneScope handles;
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(1); builder.set_locals_count(0);
builder.set_parameter_count(8); builder.set_parameter_count(8);
builder.LoadAccumulatorWithRegister(builder.Parameter(0)) builder.LoadAccumulatorWithRegister(builder.Parameter(0))
.BinaryOperation(Token::Value::ADD, builder.Parameter(1)) .BinaryOperation(Token::Value::ADD, builder.Parameter(1))
...@@ -454,3 +467,94 @@ TEST(InterpreterParameter8) { ...@@ -454,3 +467,94 @@ TEST(InterpreterParameter8) {
.ToHandleChecked(); .ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(36)); CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(36));
} }
TEST(InterpreterLoadNamedProperty) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
i::Code::Kind ic_kinds[] = { i::Code::LOAD_IC };
i::FeedbackVectorSpec feedback_spec(0, 1, ic_kinds);
Handle<i::TypeFeedbackVector> vector =
factory->NewTypeFeedbackVector(&feedback_spec);
Handle<i::String> name = factory->NewStringFromAsciiChecked("val");
name = factory->string_table()->LookupString(isolate, name);
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(0);
builder.set_parameter_count(1);
builder.LoadLiteral(name)
.LoadNamedProperty(builder.Parameter(0), vector->first_ic_slot_index(),
i::SLOPPY)
.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
auto callable = tester.GetCallable<Handle<Object>>();
Handle<Object> object = tester.NewObject("({ val : 123 })");
// Test IC miss.
Handle<Object> return_val = callable(object).ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
// Test transition to monomorphic IC.
return_val = callable(object).ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
// Test transition to polymorphic IC.
Handle<Object> object2 = tester.NewObject("({ val : 456, other : 123 })");
return_val = callable(object2).ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(456));
// Test transition to megamorphic IC.
Handle<Object> object3 = tester.NewObject("({ val : 789, val2 : 123 })");
callable(object3).ToHandleChecked();
Handle<Object> object4 = tester.NewObject("({ val : 789, val3 : 123 })");
callable(object4).ToHandleChecked();
Handle<Object> object5 = tester.NewObject("({ val : 789, val4 : 123 })");
return_val = callable(object5).ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
}
TEST(InterpreterLoadKeyedProperty) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
i::Code::Kind ic_kinds[] = { i::Code::KEYED_LOAD_IC };
i::FeedbackVectorSpec feedback_spec(0, 1, ic_kinds);
Handle<i::TypeFeedbackVector> vector =
factory->NewTypeFeedbackVector(&feedback_spec);
Handle<i::String> key = factory->NewStringFromAsciiChecked("key");
key = factory->string_table()->LookupString(isolate, key);
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
builder.set_locals_count(1);
builder.set_parameter_count(1);
builder.LoadLiteral(key)
.LoadKeyedProperty(builder.Parameter(0), vector->first_ic_slot_index(),
i::SLOPPY)
.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
auto callable = tester.GetCallable<Handle<Object>>();
Handle<Object> object = tester.NewObject("({ key : 123 })");
// Test IC miss.
Handle<Object> return_val = callable(object).ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
// Test transition to monomorphic IC.
return_val = callable(object).ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
// Test transition to megamorphic IC.
Handle<Object> object3 = tester.NewObject("({ key : 789, val2 : 123 })");
return_val = callable(object3).ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
}
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "src/compiler/graph.h" #include "src/compiler/graph.h"
#include "src/compiler/node.h" #include "src/compiler/node.h"
#include "src/interface-descriptors.h"
#include "src/isolate.h" #include "src/isolate.h"
#include "test/unittests/compiler/compiler-test-utils.h" #include "test/unittests/compiler/compiler-test-utils.h"
#include "test/unittests/compiler/node-test-utils.h" #include "test/unittests/compiler/node-test-utils.h"
...@@ -75,6 +76,14 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore( ...@@ -75,6 +76,14 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore(
} }
template <class... A>
Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsCall(
const Matcher<const CallDescriptor*>& descriptor_matcher, A... args) {
return ::i::compiler::IsCall(descriptor_matcher, args..., graph()->start(),
graph()->start());
}
Matcher<Node*> Matcher<Node*>
InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand( InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand(
int operand) { int operand) {
...@@ -339,15 +348,53 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallJSBuiltin) { ...@@ -339,15 +348,53 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallJSBuiltin) {
m.IsLoad(kMachAnyTagged, function_matcher, m.IsLoad(kMachAnyTagged, function_matcher,
IsIntPtrConstant(JSFunction::kContextOffset - kHeapObjectTag)); IsIntPtrConstant(JSFunction::kContextOffset - kHeapObjectTag));
EXPECT_THAT(call_js_builtin_0, EXPECT_THAT(call_js_builtin_0,
IsCall(_, function_matcher, receiver, context_matcher, m.IsCall(_, function_matcher, receiver, context_matcher));
m.graph()->start(), m.graph()->start()));
Node* arg1 = m.Int32Constant(0xabcd); Node* arg1 = m.Int32Constant(0xabcd);
Node* call_js_builtin_1 = Node* call_js_builtin_1 =
m.CallJSBuiltin(Context::SUB_BUILTIN_INDEX, receiver, arg1); m.CallJSBuiltin(Context::SUB_BUILTIN_INDEX, receiver, arg1);
EXPECT_THAT(call_js_builtin_1, EXPECT_THAT(call_js_builtin_1,
IsCall(_, function_matcher, receiver, arg1, context_matcher, m.IsCall(_, function_matcher, receiver, arg1, context_matcher));
m.graph()->start(), m.graph()->start())); }
}
TARGET_TEST_F(InterpreterAssemblerTest, CallIC) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode);
LoadWithVectorDescriptor descriptor(isolate());
Node* target = m.Int32Constant(1);
Node* arg1 = m.Int32Constant(2);
Node* arg2 = m.Int32Constant(3);
Node* arg3 = m.Int32Constant(4);
Node* arg4 = m.Int32Constant(5);
Node* call_ic = m.CallIC(descriptor, target, arg1, arg2, arg3, arg4);
EXPECT_THAT(call_ic,
m.IsCall(_, target, arg1, arg2, arg3, arg4,
IsParameter(Linkage::kInterpreterContextParameter)));
}
}
TARGET_TEST_F(InterpreterAssemblerTest, LoadTypeFeedbackVector) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
InterpreterAssemblerForTest m(this, bytecode);
Node* feedback_vector = m.LoadTypeFeedbackVector();
Matcher<Node*> load_function_matcher = m.IsLoad(
kMachAnyTagged, IsParameter(Linkage::kInterpreterRegisterFileParameter),
IsIntPtrConstant(
InterpreterFrameConstants::kFunctionFromRegisterPointer));
Matcher<Node*> load_shared_function_info_matcher =
m.IsLoad(kMachAnyTagged, load_function_matcher,
IsIntPtrConstant(JSFunction::kSharedFunctionInfoOffset -
kHeapObjectTag));
EXPECT_THAT(
feedback_vector,
m.IsLoad(kMachAnyTagged, load_shared_function_info_matcher,
IsIntPtrConstant(SharedFunctionInfo::kFeedbackVectorOffset -
kHeapObjectTag)));
} }
} }
......
...@@ -38,6 +38,11 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone { ...@@ -38,6 +38,11 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone {
const Matcher<Node*>& base_matcher, const Matcher<Node*>& base_matcher,
const Matcher<Node*>& index_matcher, const Matcher<Node*>& index_matcher,
const Matcher<Node*>& value_matcher); const Matcher<Node*>& value_matcher);
template <class... A>
Matcher<Node*> IsCall(
const Matcher<const CallDescriptor*>& descriptor_matcher,
A... args);
Matcher<Node*> IsBytecodeOperand(int operand); Matcher<Node*> IsBytecodeOperand(int operand);
Matcher<Node*> IsBytecodeOperandSignExtended(int operand); Matcher<Node*> IsBytecodeOperandSignExtended(int operand);
......
...@@ -39,6 +39,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -39,6 +39,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
Register reg(0); Register reg(0);
builder.LoadAccumulatorWithRegister(reg).StoreAccumulatorInRegister(reg); builder.LoadAccumulatorWithRegister(reg).StoreAccumulatorInRegister(reg);
// Emit load property operations.
builder.LoadNamedProperty(reg, 0, LanguageMode::SLOPPY);
builder.LoadKeyedProperty(reg, 0, LanguageMode::STRICT);
// Emit binary operators invocations. // Emit binary operators invocations.
builder.BinaryOperation(Token::Value::ADD, reg) builder.BinaryOperation(Token::Value::ADD, reg)
.BinaryOperation(Token::Value::SUB, reg) .BinaryOperation(Token::Value::SUB, reg)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment