[Interpreter] Add support for property load operations.
authorrmcilroy <rmcilroy@chromium.org>
Wed, 2 Sep 2015 13:03:06 +0000 (06:03 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 2 Sep 2015 13:03:22 +0000 (13:03 +0000)
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}

15 files changed:
src/compiler/interpreter-assembler.cc
src/compiler/interpreter-assembler.h
src/frames.h
src/interpreter/bytecode-array-builder.cc
src/interpreter/bytecode-array-builder.h
src/interpreter/bytecode-generator.cc
src/interpreter/bytecode-generator.h
src/interpreter/bytecodes.h
src/interpreter/interpreter.cc
src/interpreter/interpreter.h
test/cctest/interpreter/test-bytecode-generator.cc
test/cctest/interpreter/test-interpreter.cc
test/unittests/compiler/interpreter-assembler-unittest.cc
test/unittests/compiler/interpreter-assembler-unittest.h
test/unittests/interpreter/bytecode-array-builder-unittest.cc

index 6203245..d826697 100644 (file)
@@ -14,6 +14,7 @@
 #include "src/compiler/raw-machine-assembler.h"
 #include "src/compiler/schedule.h"
 #include "src/frames.h"
+#include "src/interface-descriptors.h"
 #include "src/interpreter/bytecodes.h"
 #include "src/macro-assembler.h"
 #include "src/zone.h"
@@ -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** js_args, int js_arg_count) {
   Node* global_object = LoadContextSlot(Context::GLOBAL_OBJECT_INDEX);
index bb771eb..2541d26 100644 (file)
@@ -16,6 +16,7 @@
 namespace v8 {
 namespace internal {
 
+class CallInterfaceDescriptor;
 class Isolate;
 class Zone;
 
@@ -76,6 +77,13 @@ class InterpreterAssembler {
   // Load |slot_index| from the current context.
   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.
   Node* CallJSBuiltin(int context_index, Node* receiver);
   Node* CallJSBuiltin(int context_index, Node* receiver, Node* arg1);
index 940b473..5711f39 100644 (file)
@@ -180,6 +180,7 @@ class InterpreterFrameConstants : public AllStatic {
   // Register file pointer relative.
   static const int kLastParamFromRegisterPointer =
       StandardFrameConstants::kFixedFrameSize + kPointerSize;
+  static const int kFunctionFromRegisterPointer = kPointerSize;
 };
 
 
index 989fb2d..83cf036 100644 (file)
@@ -91,7 +91,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(
 
 BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) {
   size_t entry = GetConstantPoolEntry(object);
-  if (entry <= 255) {
+  if (FitsInByteOperand(entry)) {
     Output(Bytecode::kLdaConstant, static_cast<uint8_t>(entry));
   } else {
     UNIMPLEMENTED();
@@ -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() {
   Output(Bytecode::kReturn);
   return *this;
@@ -194,9 +226,8 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
     case OperandType::kNone:
       return false;
     case OperandType::kImm8:
-      return true;
     case OperandType::kIdx:
-      return operand_value < constants_.size();
+      return true;
     case OperandType::kReg: {
       int reg_index = Register::FromOperand(operand_value).index();
       return (reg_index >= 0 && reg_index < temporary_register_next_) ||
@@ -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)
     : builder_(builder), count_(0), last_register_index_(-1) {}
 
index 8a45c73..666ec52 100644 (file)
@@ -51,6 +51,12 @@ class BytecodeArrayBuilder {
   BytecodeArrayBuilder& LoadAccumulatorWithRegister(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.
   BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg);
 
@@ -62,6 +68,8 @@ class BytecodeArrayBuilder {
       -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
 
   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);
index 8d35ea4..487b865 100644 (file)
@@ -25,6 +25,7 @@ BytecodeGenerator::~BytecodeGenerator() {}
 
 
 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
+  set_info(info);
   set_scope(info->scope());
 
   // This a temporary guard (oth).
@@ -45,6 +46,7 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
   VisitStatements(info->literal()->body());
 
   set_scope(nullptr);
+  set_info(nullptr);
   return builder_.ToBytecodeArray();
 }
 
@@ -84,17 +86,17 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
 }
 
 
-void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* node) {
+void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitImportDeclaration(ImportDeclaration* node) {
+void BytecodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* node) {
+void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
   UNIMPLEMENTED();
 }
 
@@ -104,36 +106,36 @@ void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
 }
 
 
-void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
+void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitIfStatement(IfStatement* node) { UNIMPLEMENTED(); }
+void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { UNIMPLEMENTED(); }
 
 
-void BytecodeGenerator::VisitContinueStatement(ContinueStatement* node) {
+void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitBreakStatement(BreakStatement* node) {
+void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitReturnStatement(ReturnStatement* node) {
-  Visit(node->expression());
+void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
+  Visit(stmt->expression());
   builder().Return();
 }
 
 
-void BytecodeGenerator::VisitWithStatement(WithStatement* node) {
+void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
+void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
   UNIMPLEMENTED();
 }
 
@@ -141,63 +143,63 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
 void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); }
 
 
-void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) {
+void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitWhileStatement(WhileStatement* node) {
+void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitForStatement(ForStatement* node) {
+void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitForInStatement(ForInStatement* node) {
+void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitForOfStatement(ForOfStatement* node) {
+void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) {
+void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
+void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
+void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
+void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitClassLiteral(ClassLiteral* node) {
+void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
   UNIMPLEMENTED();
 }
 
 
 void BytecodeGenerator::VisitNativeFunctionLiteral(
-    NativeFunctionLiteral* node) {
+    NativeFunctionLiteral* expr) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitConditional(Conditional* node) { UNIMPLEMENTED(); }
+void BytecodeGenerator::VisitConditional(Conditional* expr) { UNIMPLEMENTED(); }
 
 
 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();
 }
 
 
-void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
+void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
+void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
   UNIMPLEMENTED();
 }
 
@@ -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();
 }
 
 
-void BytecodeGenerator::VisitCountOperation(CountOperation* node) {
+void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
   UNIMPLEMENTED();
 }
 
@@ -328,31 +359,31 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
 }
 
 
-void BytecodeGenerator::VisitCompareOperation(CompareOperation* node) {
+void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitSpread(Spread* node) { UNREACHABLE(); }
+void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); }
 
 
-void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* node) {
+void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
   UNREACHABLE();
 }
 
 
-void BytecodeGenerator::VisitThisFunction(ThisFunction* node) {
+void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
   UNIMPLEMENTED();
 }
 
 
-void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* node) {
+void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
   UNIMPLEMENTED();
 }
 
 
 void BytecodeGenerator::VisitSuperPropertyReference(
-    SuperPropertyReference* node) {
+    SuperPropertyReference* expr) {
   UNIMPLEMENTED();
 }
 
@@ -371,6 +402,16 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) {
   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 internal
 }  // namespace v8
index 5caf3f1..080f644 100644 (file)
@@ -31,9 +31,15 @@ class BytecodeGenerator : public AstVisitor {
 
   inline BytecodeArrayBuilder& builder() { return builder_; }
   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_;
+  CompilationInfo* info_;
   Scope* scope_;
 };
 
index a5b34f7..e5097b4 100644 (file)
@@ -23,30 +23,34 @@ namespace interpreter {
   V(Reg)
 
 // The list of bytecodes which are interpreted by the interpreter.
-#define BYTECODE_LIST(V)               \
-                                       \
-  /* Loading the accumulator */        \
-  V(LdaZero, OperandType::kNone)       \
-  V(LdaSmi8, OperandType::kImm8)       \
-  V(LdaConstant, OperandType::kIdx)    \
-  V(LdaUndefined, OperandType::kNone)  \
-  V(LdaNull, OperandType::kNone)       \
-  V(LdaTheHole, OperandType::kNone)    \
-  V(LdaTrue, OperandType::kNone)       \
-  V(LdaFalse, OperandType::kNone)      \
-                                       \
-  /* Register-accumulator transfers */ \
-  V(Ldar, OperandType::kReg)           \
-  V(Star, OperandType::kReg)           \
-                                       \
-  /* Binary Operators */               \
-  V(Add, OperandType::kReg)            \
-  V(Sub, OperandType::kReg)            \
-  V(Mul, OperandType::kReg)            \
-  V(Div, OperandType::kReg)            \
-  V(Mod, OperandType::kReg)            \
-                                       \
-  /* Control Flow */                   \
+#define BYTECODE_LIST(V)                               \
+                                                       \
+  /* Loading the accumulator */                        \
+  V(LdaZero, OperandType::kNone)                       \
+  V(LdaSmi8, OperandType::kImm8)                       \
+  V(LdaConstant, OperandType::kIdx)                    \
+  V(LdaUndefined, OperandType::kNone)                  \
+  V(LdaNull, OperandType::kNone)                       \
+  V(LdaTheHole, OperandType::kNone)                    \
+  V(LdaTrue, OperandType::kNone)                       \
+  V(LdaFalse, OperandType::kNone)                      \
+                                                       \
+  /* Register-accumulator transfers */                 \
+  V(Ldar, OperandType::kReg)                           \
+  V(Star, OperandType::kReg)                           \
+                                                       \
+  /* LoadIC operations */                              \
+  V(LoadIC, OperandType::kReg, OperandType::kIdx)      \
+  V(KeyedLoadIC, OperandType::kReg, OperandType::kIdx) \
+                                                       \
+  /* Binary Operators */                               \
+  V(Add, OperandType::kReg)                            \
+  V(Sub, OperandType::kReg)                            \
+  V(Mul, OperandType::kReg)                            \
+  V(Div, OperandType::kReg)                            \
+  V(Mod, OperandType::kReg)                            \
+                                                       \
+  /* Control Flow */                                   \
   V(Return, OperandType::kNone)
 
 
index 80daf9f..334f7d3 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "src/interpreter/interpreter.h"
 
+#include "src/code-factory.h"
 #include "src/compiler.h"
 #include "src/compiler/interpreter-assembler.h"
 #include "src/factory.h"
@@ -61,6 +62,7 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) {
   Handle<SharedFunctionInfo> shared_info = info->shared_info();
 
   BytecodeGenerator generator(info->isolate(), info->zone());
+  info->EnsureFeedbackVector();
   Handle<BytecodeArray> bytecodes = generator.MakeBytecode(info);
   if (FLAG_print_bytecode) {
     bytecodes->Print();
@@ -73,7 +75,6 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) {
 
   shared_info->set_function_data(*bytecodes);
   info->SetCode(info->isolate()->builtins()->InterpreterEntryTrampoline());
-  info->EnsureFeedbackVector();
   return true;
 }
 
@@ -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,
                              compiler::InterpreterAssembler* assembler) {
   // TODO(rmcilroy): Call ICs which back-patch bytecode with type specialized
index 5ab5e37..dd7d122 100644 (file)
@@ -16,6 +16,7 @@ namespace v8 {
 namespace internal {
 
 class Isolate;
+class Callable;
 class CompilationInfo;
 
 namespace compiler {
@@ -51,6 +52,9 @@ class Interpreter {
   void DoBinaryOp(int builtin_context_index,
                   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);
 
   Isolate* isolate_;
index a9eb58a..c62e5ef 100644 (file)
@@ -17,6 +17,9 @@ class BytecodeGeneratorHelper {
  public:
   const char* kFunctionName = "f";
 
+  const int kLastParamIndex =
+      -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
+
   BytecodeGeneratorHelper() {
     i::FLAG_ignition = true;
     i::FLAG_ignition_filter = kFunctionName;
@@ -24,6 +27,9 @@ class BytecodeGeneratorHelper {
   }
 
 
+  Factory* factory() { return CcTest::i_isolate()->factory(); }
+
+
   Handle<BytecodeArray> MakeBytecode(const char* script,
                                      const char* function_name) {
     CompileRun(script);
@@ -52,11 +58,11 @@ class BytecodeGeneratorHelper {
 // Structure for containing expected bytecode snippets.
 template<typename T>
 struct ExpectedSnippet {
-  const char* body;
+  const char* code_snippet;
   int frame_size;
   int parameter_count;
   int bytecode_length;
-  const uint8_t bytecode[16];
+  const uint8_t bytecode[24];
   int constant_count;
   T constants[16];
 };
@@ -87,7 +93,7 @@ TEST(PrimitiveReturnStatements) {
   size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
   for (size_t i = 0; i < num_snippets; i++) {
     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->parameter_count(), snippets[i].parameter_count);
     CHECK_EQ(ba->length(), snippets[i].bytecode_length);
@@ -134,7 +140,7 @@ TEST(PrimitiveExpressions) {
   size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
   for (size_t i = 0; i < num_snippets; i++) {
     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->parameter_count(), snippets[i].parameter_count);
     CHECK_EQ(ba->length(), snippets[i].bytecode_length);
@@ -149,24 +155,23 @@ TEST(Parameters) {
   InitializedHandleScope handle_scope;
   BytecodeGeneratorHelper helper;
 
-  int last_param_index =
-      -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
   ExpectedSnippet<void*> snippets[] = {
       {"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; }",
-       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; }",
-       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; }",
-       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; }",
-       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]);
   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->parameter_count(), snippets[i].parameter_count);
     CHECK_EQ(ba->length(), snippets[i].bytecode_length);
@@ -212,7 +217,7 @@ TEST(Constants) {
     size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
     for (size_t i = 0; i < num_snippets; i++) {
       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->parameter_count(), snippets[i].parameter_count);
       CHECK_EQ(ba->length(), snippets[i].bytecode_length);
@@ -261,7 +266,7 @@ TEST(Constants) {
     size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
     for (size_t i = 0; i < num_snippets; i++) {
       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->parameter_count(), snippets[i].parameter_count);
       CHECK_EQ(ba->length(), snippets[i].bytecode_length);
@@ -308,7 +313,7 @@ TEST(Constants) {
     size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
     for (size_t i = 0; i < num_snippets; i++) {
       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->parameter_count(), snippets[i].parameter_count);
       CHECK_EQ(ba->length(), snippets[i].bytecode_length);
@@ -316,9 +321,8 @@ TEST(Constants) {
                     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 =
-            CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(
-                snippets[i].constants[j]);
+        Handle<String> expected = helper.factory()->NewStringFromAsciiChecked(
+            snippets[i].constants[j]);
         CHECK(String::cast(ba->constant_pool()->get(j))->Equals(*expected));
       }
     }
@@ -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 internal
 }  // namespance v8
index 397d700..56fa4c6 100644 (file)
@@ -53,8 +53,12 @@ class InterpreterCallable {
 
 class InterpreterTester {
  public:
-  InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode)
-      : isolate_(isolate), bytecode_(bytecode) {
+  InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode,
+                    MaybeHandle<TypeFeedbackVector> feedback_vector =
+                        MaybeHandle<TypeFeedbackVector>())
+      : isolate_(isolate),
+        bytecode_(bytecode),
+        feedback_vector_(feedback_vector) {
     i::FLAG_ignition = true;
     // Ensure handler table is generated.
     isolate->interpreter()->Initialize();
@@ -66,9 +70,14 @@ class InterpreterTester {
     return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>());
   }
 
+  Handle<Object> NewObject(const char* script) {
+    return v8::Utils::OpenHandle(*CompileRun(script));
+  }
+
  private:
   Isolate* isolate_;
   Handle<BytecodeArray> bytecode_;
+  MaybeHandle<TypeFeedbackVector> feedback_vector_;
 
   template <class... A>
   Handle<JSFunction> GetBytecodeFunction() {
@@ -83,6 +92,10 @@ class InterpreterTester {
         *v8::Handle<v8::Function>::Cast(CompileRun(function_text.c_str())));
     function->ReplaceCode(*isolate_->builtins()->InterpreterEntryTrampoline());
     function->shared()->set_function_data(*bytecode_);
+    if (!feedback_vector_.is_null()) {
+      function->shared()->set_feedback_vector(
+          *feedback_vector_.ToHandleChecked());
+    }
     return function;
   }
 
@@ -400,7 +413,7 @@ TEST(InterpreterMod) {
 TEST(InterpreterParameter1) {
   HandleAndZoneScope handles;
   BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
-  builder.set_locals_count(1);
+  builder.set_locals_count(0);
   builder.set_parameter_count(1);
   builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return();
   Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
@@ -423,7 +436,7 @@ TEST(InterpreterParameter1) {
 TEST(InterpreterParameter8) {
   HandleAndZoneScope handles;
   BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
-  builder.set_locals_count(1);
+  builder.set_locals_count(0);
   builder.set_parameter_count(8);
   builder.LoadAccumulatorWithRegister(builder.Parameter(0))
       .BinaryOperation(Token::Value::ADD, builder.Parameter(1))
@@ -454,3 +467,94 @@ TEST(InterpreterParameter8) {
           .ToHandleChecked();
   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));
+}
index e1d1933..9e6eff3 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "src/compiler/graph.h"
 #include "src/compiler/node.h"
+#include "src/interface-descriptors.h"
 #include "src/isolate.h"
 #include "test/unittests/compiler/compiler-test-utils.h"
 #include "test/unittests/compiler/node-test-utils.h"
@@ -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*>
 InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand(
     int operand) {
@@ -339,15 +348,53 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallJSBuiltin) {
         m.IsLoad(kMachAnyTagged, function_matcher,
                  IsIntPtrConstant(JSFunction::kContextOffset - kHeapObjectTag));
     EXPECT_THAT(call_js_builtin_0,
-                IsCall(_, function_matcher, receiver, context_matcher,
-                       m.graph()->start(), m.graph()->start()));
+                m.IsCall(_, function_matcher, receiver, context_matcher));
 
     Node* arg1 = m.Int32Constant(0xabcd);
     Node* call_js_builtin_1 =
         m.CallJSBuiltin(Context::SUB_BUILTIN_INDEX, receiver, arg1);
     EXPECT_THAT(call_js_builtin_1,
-                IsCall(_, function_matcher, receiver, arg1, context_matcher,
-                       m.graph()->start(), m.graph()->start()));
+                m.IsCall(_, function_matcher, receiver, arg1, context_matcher));
+  }
+}
+
+
+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)));
   }
 }
 
index 64353ae..0ed91eb 100644 (file)
@@ -38,6 +38,11 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone {
                            const Matcher<Node*>& base_matcher,
                            const Matcher<Node*>& index_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*> IsBytecodeOperandSignExtended(int operand);
 
index 96c8846..353ab15 100644 (file)
@@ -39,6 +39,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
   Register reg(0);
   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.
   builder.BinaryOperation(Token::Value::ADD, reg)
       .BinaryOperation(Token::Value::SUB, reg)