[Interpreter] Add support for for count operations.
Adds support for count operations to the interpreter. Deals with count operations on locals, globals, context allocated variables and named and keyed properties. Adds the following bytecodes: ToNumber Inc Dec BUG=v8:4280 LOG=N TBR=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/1416623003 Cr-Commit-Position: refs/heads/master@{#31484}
This commit is contained in:
parent
5676415b4a
commit
0030805643
@ -476,6 +476,18 @@ void BytecodeGraphBuilder::VisitShiftRightLogical(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BytecodeGraphBuilder::VisitInc(
|
||||||
|
const interpreter::BytecodeArrayIterator& iterator) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BytecodeGraphBuilder::VisitDec(
|
||||||
|
const interpreter::BytecodeArrayIterator& iterator) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void BytecodeGraphBuilder::VisitLogicalNot(
|
void BytecodeGraphBuilder::VisitLogicalNot(
|
||||||
const interpreter::BytecodeArrayIterator& iterator) {
|
const interpreter::BytecodeArrayIterator& iterator) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
@ -560,6 +572,12 @@ void BytecodeGraphBuilder::VisitToName(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BytecodeGraphBuilder::VisitToNumber(
|
||||||
|
const interpreter::BytecodeArrayIterator& iterator) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void BytecodeGraphBuilder::VisitJump(
|
void BytecodeGraphBuilder::VisitJump(
|
||||||
const interpreter::BytecodeArrayIterator& iterator) {
|
const interpreter::BytecodeArrayIterator& iterator) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
|
@ -172,6 +172,17 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op,
|
||||||
|
Strength strength) {
|
||||||
|
if (is_strong(strength)) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Output(BytecodeForCountOperation(op));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
|
BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
|
||||||
Output(Bytecode::kLogicalNot);
|
Output(Bytecode::kLogicalNot);
|
||||||
return *this;
|
return *this;
|
||||||
@ -465,6 +476,14 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToNumber() {
|
||||||
|
// TODO(rmcilroy): consider omitting if the preceeding bytecode always returns
|
||||||
|
// a number.
|
||||||
|
Output(Bytecode::kToNumber);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
|
BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(BytecodeLabel* label) {
|
||||||
if (label->is_forward_target()) {
|
if (label->is_forward_target()) {
|
||||||
// An earlier jump instruction refers to this label. Update it's location.
|
// An earlier jump instruction refers to this label. Update it's location.
|
||||||
@ -826,6 +845,20 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) {
|
||||||
|
switch (op) {
|
||||||
|
case Token::Value::ADD:
|
||||||
|
return Bytecode::kInc;
|
||||||
|
case Token::Value::SUB:
|
||||||
|
return Bytecode::kDec;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
return static_cast<Bytecode>(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
|
Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
@ -146,6 +146,9 @@ class BytecodeArrayBuilder {
|
|||||||
BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg,
|
BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg,
|
||||||
Strength strength);
|
Strength strength);
|
||||||
|
|
||||||
|
// Count Operators (value stored in accumulator).
|
||||||
|
BytecodeArrayBuilder& CountOperation(Token::Value op, Strength strength);
|
||||||
|
|
||||||
// Unary Operators.
|
// Unary Operators.
|
||||||
BytecodeArrayBuilder& LogicalNot();
|
BytecodeArrayBuilder& LogicalNot();
|
||||||
BytecodeArrayBuilder& TypeOf();
|
BytecodeArrayBuilder& TypeOf();
|
||||||
@ -157,6 +160,7 @@ class BytecodeArrayBuilder {
|
|||||||
// Casts.
|
// Casts.
|
||||||
BytecodeArrayBuilder& CastAccumulatorToBoolean();
|
BytecodeArrayBuilder& CastAccumulatorToBoolean();
|
||||||
BytecodeArrayBuilder& CastAccumulatorToName();
|
BytecodeArrayBuilder& CastAccumulatorToName();
|
||||||
|
BytecodeArrayBuilder& CastAccumulatorToNumber();
|
||||||
|
|
||||||
// Flow Control.
|
// Flow Control.
|
||||||
BytecodeArrayBuilder& Bind(BytecodeLabel* label);
|
BytecodeArrayBuilder& Bind(BytecodeLabel* label);
|
||||||
@ -186,6 +190,7 @@ class BytecodeArrayBuilder {
|
|||||||
Isolate* isolate() const { return isolate_; }
|
Isolate* isolate() const { return isolate_; }
|
||||||
|
|
||||||
static Bytecode BytecodeForBinaryOperation(Token::Value op);
|
static Bytecode BytecodeForBinaryOperation(Token::Value op);
|
||||||
|
static Bytecode BytecodeForCountOperation(Token::Value op);
|
||||||
static Bytecode BytecodeForCompareOperation(Token::Value op);
|
static Bytecode BytecodeForCompareOperation(Token::Value op);
|
||||||
static Bytecode BytecodeForLoadIC(LanguageMode language_mode);
|
static Bytecode BytecodeForLoadIC(LanguageMode language_mode);
|
||||||
static Bytecode BytecodeForKeyedLoadIC(LanguageMode language_mode);
|
static Bytecode BytecodeForKeyedLoadIC(LanguageMode language_mode);
|
||||||
|
@ -960,6 +960,21 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BytecodeGenerator::VisitVariableLoadForAccumulatorValue(
|
||||||
|
Variable* variable, FeedbackVectorSlot slot) {
|
||||||
|
AccumulatorResultScope accumulator_result(this);
|
||||||
|
VisitVariableLoad(variable, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Register BytecodeGenerator::VisitVariableLoadForRegisterValue(
|
||||||
|
Variable* variable, FeedbackVectorSlot slot) {
|
||||||
|
RegisterResultScope register_scope(this);
|
||||||
|
VisitVariableLoad(variable, slot);
|
||||||
|
return register_scope.ResultRegister();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
|
void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
|
||||||
FeedbackVectorSlot slot) {
|
FeedbackVectorSlot slot) {
|
||||||
switch (variable->location()) {
|
switch (variable->location()) {
|
||||||
@ -1174,10 +1189,8 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
|||||||
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
|
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
|
||||||
// Load callee as a global variable.
|
// Load callee as a global variable.
|
||||||
VariableProxy* proxy = callee_expr->AsVariableProxy();
|
VariableProxy* proxy = callee_expr->AsVariableProxy();
|
||||||
// Result scope for VisitVariableLoad to avoid using our temporaries
|
VisitVariableLoadForAccumulatorValue(proxy->var(),
|
||||||
// and double setting the result in our result_scope() and.
|
proxy->VariableFeedbackSlot());
|
||||||
AccumulatorResultScope accumulator_execution_result(this);
|
|
||||||
VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot());
|
|
||||||
builder()->StoreAccumulatorInRegister(callee);
|
builder()->StoreAccumulatorInRegister(callee);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1295,7 +1308,93 @@ void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
|||||||
|
|
||||||
|
|
||||||
void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
|
void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||||
UNIMPLEMENTED();
|
DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
|
||||||
|
|
||||||
|
// Left-hand side can only be a property, a global or a variable slot.
|
||||||
|
Property* property = expr->expression()->AsProperty();
|
||||||
|
LhsKind assign_type = Property::GetAssignType(property);
|
||||||
|
|
||||||
|
// TODO(rmcilroy): Set is_postfix to false if visiting for effect.
|
||||||
|
bool is_postfix = expr->is_postfix();
|
||||||
|
|
||||||
|
// Evaluate LHS expression and get old value.
|
||||||
|
Register obj, key, old_value;
|
||||||
|
size_t name_index = kMaxUInt32;
|
||||||
|
switch (assign_type) {
|
||||||
|
case VARIABLE: {
|
||||||
|
VariableProxy* proxy = expr->expression()->AsVariableProxy();
|
||||||
|
VisitVariableLoadForAccumulatorValue(proxy->var(),
|
||||||
|
proxy->VariableFeedbackSlot());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NAMED_PROPERTY: {
|
||||||
|
FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
|
||||||
|
obj = VisitForRegisterValue(property->obj());
|
||||||
|
name_index = builder()->GetConstantPoolEntry(
|
||||||
|
property->key()->AsLiteral()->AsPropertyName());
|
||||||
|
builder()->LoadNamedProperty(obj, name_index, feedback_index(slot),
|
||||||
|
language_mode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KEYED_PROPERTY: {
|
||||||
|
FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
|
||||||
|
obj = VisitForRegisterValue(property->obj());
|
||||||
|
// Use visit for accumulator here since we need the key in the accumulator
|
||||||
|
// for the LoadKeyedProperty.
|
||||||
|
key = execution_result()->NewRegister();
|
||||||
|
VisitForAccumulatorValue(property->key());
|
||||||
|
builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty(
|
||||||
|
obj, feedback_index(slot), language_mode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NAMED_SUPER_PROPERTY:
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert old value into a number.
|
||||||
|
if (!is_strong(language_mode())) {
|
||||||
|
builder()->CastAccumulatorToNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save result for postfix expressions.
|
||||||
|
if (is_postfix) {
|
||||||
|
old_value = execution_result()->NewRegister();
|
||||||
|
builder()->StoreAccumulatorInRegister(old_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform +1/-1 operation.
|
||||||
|
builder()->CountOperation(expr->binary_op(), language_mode_strength());
|
||||||
|
|
||||||
|
// Store the value.
|
||||||
|
FeedbackVectorSlot feedback_slot = expr->CountSlot();
|
||||||
|
switch (assign_type) {
|
||||||
|
case VARIABLE: {
|
||||||
|
Variable* variable = expr->expression()->AsVariableProxy()->var();
|
||||||
|
VisitVariableAssignment(variable, feedback_slot);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NAMED_PROPERTY: {
|
||||||
|
builder()->StoreNamedProperty(
|
||||||
|
obj, name_index, feedback_index(feedback_slot), language_mode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KEYED_PROPERTY: {
|
||||||
|
builder()->StoreKeyedProperty(obj, key, feedback_index(feedback_slot),
|
||||||
|
language_mode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NAMED_SUPER_PROPERTY:
|
||||||
|
case KEYED_SUPER_PROPERTY:
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore old value for postfix expressions.
|
||||||
|
if (is_postfix) {
|
||||||
|
execution_result()->SetResultInRegister(old_value);
|
||||||
|
} else {
|
||||||
|
execution_result()->SetResultInAccumulator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,17 +41,28 @@ class BytecodeGenerator : public AstVisitor {
|
|||||||
|
|
||||||
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
|
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
|
||||||
|
|
||||||
Register VisitArguments(ZoneList<Expression*>* arguments);
|
// Dispatched from VisitBinaryOperation.
|
||||||
|
|
||||||
void VisitArithmeticExpression(BinaryOperation* binop);
|
void VisitArithmeticExpression(BinaryOperation* binop);
|
||||||
void VisitCommaExpression(BinaryOperation* binop);
|
void VisitCommaExpression(BinaryOperation* binop);
|
||||||
void VisitLogicalOrExpression(BinaryOperation* binop);
|
void VisitLogicalOrExpression(BinaryOperation* binop);
|
||||||
void VisitLogicalAndExpression(BinaryOperation* binop);
|
void VisitLogicalAndExpression(BinaryOperation* binop);
|
||||||
|
|
||||||
|
// Dispatched from VisitUnaryOperation.
|
||||||
|
void VisitVoid(UnaryOperation* expr);
|
||||||
|
void VisitTypeOf(UnaryOperation* expr);
|
||||||
|
void VisitNot(UnaryOperation* expr);
|
||||||
|
|
||||||
|
// Helper visitors which perform common operations.
|
||||||
|
Register VisitArguments(ZoneList<Expression*>* arguments);
|
||||||
|
|
||||||
void VisitPropertyLoad(Register obj, Property* expr);
|
void VisitPropertyLoad(Register obj, Property* expr);
|
||||||
void VisitPropertyLoadForAccumulator(Register obj, Property* expr);
|
void VisitPropertyLoadForAccumulator(Register obj, Property* expr);
|
||||||
|
|
||||||
void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot);
|
void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot);
|
||||||
|
void VisitVariableLoadForAccumulatorValue(Variable* variable,
|
||||||
|
FeedbackVectorSlot slot);
|
||||||
|
MUST_USE_RESULT Register VisitVariableLoadForRegisterValue(
|
||||||
|
Variable* variable, FeedbackVectorSlot slot);
|
||||||
void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot);
|
void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot);
|
||||||
|
|
||||||
void VisitNewLocalFunctionContext();
|
void VisitNewLocalFunctionContext();
|
||||||
@ -64,10 +75,6 @@ class BytecodeGenerator : public AstVisitor {
|
|||||||
ObjectLiteralProperty* property,
|
ObjectLiteralProperty* property,
|
||||||
Register value_out);
|
Register value_out);
|
||||||
|
|
||||||
// Dispatched from VisitUnaryOperation.
|
|
||||||
void VisitVoid(UnaryOperation* expr);
|
|
||||||
void VisitTypeOf(UnaryOperation* expr);
|
|
||||||
void VisitNot(UnaryOperation* expr);
|
|
||||||
|
|
||||||
// Visitors for obtaining expression result in the accumulator, in a
|
// Visitors for obtaining expression result in the accumulator, in a
|
||||||
// register, or just getting the effect.
|
// register, or just getting the effect.
|
||||||
|
@ -87,6 +87,8 @@ namespace interpreter {
|
|||||||
V(ShiftRightLogical, OperandType::kReg8) \
|
V(ShiftRightLogical, OperandType::kReg8) \
|
||||||
\
|
\
|
||||||
/* Unary Operators */ \
|
/* Unary Operators */ \
|
||||||
|
V(Inc, OperandType::kNone) \
|
||||||
|
V(Dec, OperandType::kNone) \
|
||||||
V(LogicalNot, OperandType::kNone) \
|
V(LogicalNot, OperandType::kNone) \
|
||||||
V(TypeOf, OperandType::kNone) \
|
V(TypeOf, OperandType::kNone) \
|
||||||
\
|
\
|
||||||
@ -113,6 +115,7 @@ namespace interpreter {
|
|||||||
/* Cast operators */ \
|
/* Cast operators */ \
|
||||||
V(ToBoolean, OperandType::kNone) \
|
V(ToBoolean, OperandType::kNone) \
|
||||||
V(ToName, OperandType::kNone) \
|
V(ToName, OperandType::kNone) \
|
||||||
|
V(ToNumber, OperandType::kNone) \
|
||||||
\
|
\
|
||||||
/* Literals */ \
|
/* Literals */ \
|
||||||
V(CreateRegExpLiteral, OperandType::kIdx8, OperandType::kReg8) \
|
V(CreateRegExpLiteral, OperandType::kIdx8, OperandType::kReg8) \
|
||||||
|
@ -591,6 +591,32 @@ void Interpreter::DoShiftRightLogical(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Interpreter::DoCountOp(Runtime::FunctionId function_id,
|
||||||
|
compiler::InterpreterAssembler* assembler) {
|
||||||
|
Node* value = __ GetAccumulator();
|
||||||
|
Node* one = __ NumberConstant(1);
|
||||||
|
Node* result = __ CallRuntime(function_id, value, one);
|
||||||
|
__ SetAccumulator(result);
|
||||||
|
__ Dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Inc
|
||||||
|
//
|
||||||
|
// Increments value in the accumulator by one.
|
||||||
|
void Interpreter::DoInc(compiler::InterpreterAssembler* assembler) {
|
||||||
|
DoCountOp(Runtime::kAdd, assembler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Dec
|
||||||
|
//
|
||||||
|
// Decrements value in the accumulator by one.
|
||||||
|
void Interpreter::DoDec(compiler::InterpreterAssembler* assembler) {
|
||||||
|
DoCountOp(Runtime::kSubtract, assembler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// LogicalNot
|
// LogicalNot
|
||||||
//
|
//
|
||||||
// Perform logical-not on the accumulator, first casting the
|
// Perform logical-not on the accumulator, first casting the
|
||||||
@ -776,6 +802,17 @@ void Interpreter::DoToName(compiler::InterpreterAssembler* assembler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ToNumber
|
||||||
|
//
|
||||||
|
// Cast the object referenced by the accumulator to a number.
|
||||||
|
void Interpreter::DoToNumber(compiler::InterpreterAssembler* assembler) {
|
||||||
|
Node* accumulator = __ GetAccumulator();
|
||||||
|
Node* result = __ CallRuntime(Runtime::kToNumber, accumulator);
|
||||||
|
__ SetAccumulator(result);
|
||||||
|
__ Dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Jump <imm8>
|
// Jump <imm8>
|
||||||
//
|
//
|
||||||
// Jump by number of bytes represented by the immediate operand |imm8|.
|
// Jump by number of bytes represented by the immediate operand |imm8|.
|
||||||
|
@ -54,6 +54,10 @@ class Interpreter {
|
|||||||
void DoBinaryOp(Runtime::FunctionId function_id,
|
void DoBinaryOp(Runtime::FunctionId function_id,
|
||||||
compiler::InterpreterAssembler* assembler);
|
compiler::InterpreterAssembler* assembler);
|
||||||
|
|
||||||
|
// Generates code to perform the count operations via |function_id|.
|
||||||
|
void DoCountOp(Runtime::FunctionId function_id,
|
||||||
|
compiler::InterpreterAssembler* assembler);
|
||||||
|
|
||||||
// Generates code to perform the comparison operation associated with
|
// Generates code to perform the comparison operation associated with
|
||||||
// |compare_op|.
|
// |compare_op|.
|
||||||
void DoCompareOp(Token::Value compare_op,
|
void DoCompareOp(Token::Value compare_op,
|
||||||
|
@ -2916,6 +2916,295 @@ TEST(ContextParameters) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(CountOperators) {
|
||||||
|
InitializedHandleScope handle_scope;
|
||||||
|
BytecodeGeneratorHelper helper;
|
||||||
|
Zone zone;
|
||||||
|
|
||||||
|
FeedbackVectorSpec feedback_spec(&zone);
|
||||||
|
FeedbackVectorSlot slot1 = feedback_spec.AddLoadICSlot();
|
||||||
|
FeedbackVectorSlot slot2 = feedback_spec.AddStoreICSlot();
|
||||||
|
|
||||||
|
Handle<i::TypeFeedbackVector> vector =
|
||||||
|
i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec);
|
||||||
|
|
||||||
|
int closure = Register::function_closure().index();
|
||||||
|
int first_context_slot = Context::MIN_CONTEXT_SLOTS;
|
||||||
|
|
||||||
|
int object_literal_flags =
|
||||||
|
ObjectLiteral::kFastElements | ObjectLiteral::kDisableMementos;
|
||||||
|
|
||||||
|
ExpectedSnippet<InstanceType> snippets[] = {
|
||||||
|
{"var a = 1; return ++a;",
|
||||||
|
1 * kPointerSize,
|
||||||
|
1,
|
||||||
|
11,
|
||||||
|
{
|
||||||
|
B(LdaSmi8), U8(1), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(Ldar), R(0), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Inc), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(Return), //
|
||||||
|
}},
|
||||||
|
{"var a = 1; return a++;",
|
||||||
|
2 * kPointerSize,
|
||||||
|
1,
|
||||||
|
15,
|
||||||
|
{
|
||||||
|
B(LdaSmi8), U8(1), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(Ldar), R(0), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Star), R(1), //
|
||||||
|
B(Inc), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(Ldar), R(1), //
|
||||||
|
B(Return), //
|
||||||
|
}},
|
||||||
|
{"var a = 1; return --a;",
|
||||||
|
1 * kPointerSize,
|
||||||
|
1,
|
||||||
|
11,
|
||||||
|
{
|
||||||
|
B(LdaSmi8), U8(1), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(Ldar), R(0), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Dec), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(Return), //
|
||||||
|
}},
|
||||||
|
{"var a = 1; return a--;",
|
||||||
|
2 * kPointerSize,
|
||||||
|
1,
|
||||||
|
15,
|
||||||
|
{
|
||||||
|
B(LdaSmi8), U8(1), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(Ldar), R(0), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Star), R(1), //
|
||||||
|
B(Dec), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(Ldar), R(1), //
|
||||||
|
B(Return), //
|
||||||
|
}},
|
||||||
|
{"var a = { val: 1 }; return a.val++;",
|
||||||
|
2 * kPointerSize,
|
||||||
|
1,
|
||||||
|
22,
|
||||||
|
{
|
||||||
|
B(LdaConstant), U8(0), //
|
||||||
|
B(CreateObjectLiteral), U8(0), U8(object_literal_flags), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(LoadICSloppy), R(0), U8(1), U8(vector->GetIndex(slot1)), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Star), R(1), //
|
||||||
|
B(Inc), //
|
||||||
|
B(StoreICSloppy), R(0), U8(1), U8(vector->GetIndex(slot2)), //
|
||||||
|
B(Ldar), R(1), //
|
||||||
|
B(Return), //
|
||||||
|
},
|
||||||
|
2,
|
||||||
|
{InstanceType::FIXED_ARRAY_TYPE,
|
||||||
|
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}},
|
||||||
|
{"var a = { val: 1 }; return --a.val;",
|
||||||
|
1 * kPointerSize,
|
||||||
|
1,
|
||||||
|
18,
|
||||||
|
{
|
||||||
|
B(LdaConstant), U8(0), //
|
||||||
|
B(CreateObjectLiteral), U8(0), U8(object_literal_flags), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(LoadICSloppy), R(0), U8(1), U8(vector->GetIndex(slot1)), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Dec), //
|
||||||
|
B(StoreICSloppy), R(0), U8(1), U8(vector->GetIndex(slot2)), //
|
||||||
|
B(Return), //
|
||||||
|
},
|
||||||
|
2,
|
||||||
|
{InstanceType::FIXED_ARRAY_TYPE,
|
||||||
|
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}},
|
||||||
|
{"var name = 'var'; var a = { val: 1 }; return a[name]--;",
|
||||||
|
4 * kPointerSize,
|
||||||
|
1,
|
||||||
|
29,
|
||||||
|
{
|
||||||
|
B(LdaConstant), U8(0), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(LdaConstant), U8(1), //
|
||||||
|
B(CreateObjectLiteral), U8(0), U8(object_literal_flags), //
|
||||||
|
B(Star), R(1), //
|
||||||
|
B(Ldar), R(0), //
|
||||||
|
B(Star), R(2), //
|
||||||
|
B(KeyedLoadICSloppy), R(1), U8(vector->GetIndex(slot1)), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Star), R(3), //
|
||||||
|
B(Dec), //
|
||||||
|
B(KeyedStoreICSloppy), R(1), R(2), U8(vector->GetIndex(slot2)), //
|
||||||
|
B(Ldar), R(3), //
|
||||||
|
B(Return), //
|
||||||
|
},
|
||||||
|
2,
|
||||||
|
{InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
|
||||||
|
InstanceType::FIXED_ARRAY_TYPE}},
|
||||||
|
{"var name = 'var'; var a = { val: 1 }; return ++a[name];",
|
||||||
|
3 * kPointerSize,
|
||||||
|
1,
|
||||||
|
25,
|
||||||
|
{
|
||||||
|
B(LdaConstant), U8(0), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(LdaConstant), U8(1), //
|
||||||
|
B(CreateObjectLiteral), U8(0), U8(object_literal_flags), //
|
||||||
|
B(Star), R(1), //
|
||||||
|
B(Ldar), R(0), //
|
||||||
|
B(Star), R(2), //
|
||||||
|
B(KeyedLoadICSloppy), R(1), U8(vector->GetIndex(slot1)), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Inc), //
|
||||||
|
B(KeyedStoreICSloppy), R(1), R(2), U8(vector->GetIndex(slot2)), //
|
||||||
|
B(Return), //
|
||||||
|
},
|
||||||
|
2,
|
||||||
|
{InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
|
||||||
|
InstanceType::FIXED_ARRAY_TYPE}},
|
||||||
|
{"var a = 1; var b = function() { return a }; return ++a;",
|
||||||
|
2 * kPointerSize,
|
||||||
|
1,
|
||||||
|
27,
|
||||||
|
{
|
||||||
|
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
|
||||||
|
U8(1), //
|
||||||
|
B(PushContext), R(1), //
|
||||||
|
B(LdaSmi8), U8(1), //
|
||||||
|
B(StaContextSlot), R(1), U8(first_context_slot), //
|
||||||
|
B(LdaConstant), U8(0), //
|
||||||
|
B(CreateClosure), U8(0), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(LdaContextSlot), R(1), U8(first_context_slot), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Inc), //
|
||||||
|
B(StaContextSlot), R(1), U8(first_context_slot), //
|
||||||
|
B(Return), //
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||||
|
{"var a = 1; var b = function() { return a }; return a--;",
|
||||||
|
3 * kPointerSize,
|
||||||
|
1,
|
||||||
|
31,
|
||||||
|
{
|
||||||
|
B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), //
|
||||||
|
U8(1), //
|
||||||
|
B(PushContext), R(1), //
|
||||||
|
B(LdaSmi8), U8(1), //
|
||||||
|
B(StaContextSlot), R(1), U8(first_context_slot), //
|
||||||
|
B(LdaConstant), U8(0), //
|
||||||
|
B(CreateClosure), U8(0), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(LdaContextSlot), R(1), U8(first_context_slot), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Star), R(2), //
|
||||||
|
B(Dec), //
|
||||||
|
B(StaContextSlot), R(1), U8(first_context_slot), //
|
||||||
|
B(Ldar), R(2), //
|
||||||
|
B(Return), //
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arraysize(snippets); i++) {
|
||||||
|
Handle<BytecodeArray> bytecode_array =
|
||||||
|
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
|
||||||
|
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(GlobalCountOperators) {
|
||||||
|
InitializedHandleScope handle_scope;
|
||||||
|
BytecodeGeneratorHelper helper;
|
||||||
|
Zone zone;
|
||||||
|
|
||||||
|
FeedbackVectorSpec feedback_spec(&zone);
|
||||||
|
FeedbackVectorSlot slot1 = feedback_spec.AddLoadICSlot();
|
||||||
|
FeedbackVectorSlot slot2 = feedback_spec.AddStoreICSlot();
|
||||||
|
|
||||||
|
Handle<i::TypeFeedbackVector> vector =
|
||||||
|
i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec);
|
||||||
|
|
||||||
|
ExpectedSnippet<const char*> snippets[] = {
|
||||||
|
{"var global = 1;\nfunction f() { return ++global; }\nf()",
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
9,
|
||||||
|
{
|
||||||
|
B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot1)), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Inc), //
|
||||||
|
B(StaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), //
|
||||||
|
B(Return), //
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
{"global"}},
|
||||||
|
{"var global = 1;\nfunction f() { return global--; }\nf()",
|
||||||
|
1 * kPointerSize,
|
||||||
|
1,
|
||||||
|
13,
|
||||||
|
{
|
||||||
|
B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot1)), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(Dec), //
|
||||||
|
B(StaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), //
|
||||||
|
B(Ldar), R(0), //
|
||||||
|
B(Return),
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
{"global"}},
|
||||||
|
{"unallocated = 1;\nfunction f() { 'use strict'; return --unallocated; }"
|
||||||
|
"f()",
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
9,
|
||||||
|
{
|
||||||
|
B(LdaGlobalStrict), U8(0), U8(vector->GetIndex(slot1)), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Dec), //
|
||||||
|
B(StaGlobalStrict), U8(0), U8(vector->GetIndex(slot2)), //
|
||||||
|
B(Return), //
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
{"unallocated"}},
|
||||||
|
{"unallocated = 1;\nfunction f() { return unallocated++; }\nf()",
|
||||||
|
1 * kPointerSize,
|
||||||
|
1,
|
||||||
|
13,
|
||||||
|
{
|
||||||
|
B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot1)), //
|
||||||
|
B(ToNumber), //
|
||||||
|
B(Star), R(0), //
|
||||||
|
B(Inc), //
|
||||||
|
B(StaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), //
|
||||||
|
B(Ldar), R(0), //
|
||||||
|
B(Return),
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
{"unallocated"}},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arraysize(snippets); i++) {
|
||||||
|
Handle<BytecodeArray> bytecode_array =
|
||||||
|
helper.MakeBytecode(snippets[i].code_snippet, "f");
|
||||||
|
CheckBytecodeArrayEqual(snippets[i], bytecode_array, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace interpreter
|
} // namespace interpreter
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -1724,11 +1724,11 @@ TEST(InterpreterArrayLiterals) {
|
|||||||
std::make_pair("return [][0];\n",
|
std::make_pair("return [][0];\n",
|
||||||
factory->undefined_value()),
|
factory->undefined_value()),
|
||||||
std::make_pair("return [1, 3, 2][1];\n",
|
std::make_pair("return [1, 3, 2][1];\n",
|
||||||
Handle<Object>(Smi::FromInt(3), isolate)),
|
handle(Smi::FromInt(3), isolate)),
|
||||||
std::make_pair("return ['a', 'b', 'c'][2];\n",
|
std::make_pair("return ['a', 'b', 'c'][2];\n",
|
||||||
factory->NewStringFromStaticChars("c")),
|
factory->NewStringFromStaticChars("c")),
|
||||||
std::make_pair("var a = 100; return [a, a + 1, a + 2, a + 3][2];\n",
|
std::make_pair("var a = 100; return [a, a + 1, a + 2, a + 3][2];\n",
|
||||||
Handle<Object>(Smi::FromInt(102), isolate)),
|
handle(Smi::FromInt(102), isolate)),
|
||||||
std::make_pair("return [[1, 2, 3], ['a', 'b', 'c']][1][0];\n",
|
std::make_pair("return [[1, 2, 3], ['a', 'b', 'c']][1][0];\n",
|
||||||
factory->NewStringFromStaticChars("a")),
|
factory->NewStringFromStaticChars("a")),
|
||||||
std::make_pair("var t = 't'; return [[t, t + 'est'], [1 + t]][0][1];\n",
|
std::make_pair("var t = 't'; return [[t, t + 'est'], [1 + t]][0][1];\n",
|
||||||
@ -1757,26 +1757,26 @@ TEST(InterpreterObjectLiterals) {
|
|||||||
std::make_pair("return { name: 'string', val: 9.2 }.name;",
|
std::make_pair("return { name: 'string', val: 9.2 }.name;",
|
||||||
factory->NewStringFromStaticChars("string")),
|
factory->NewStringFromStaticChars("string")),
|
||||||
std::make_pair("var a = 15; return { name: 'string', val: a }.val;",
|
std::make_pair("var a = 15; return { name: 'string', val: a }.val;",
|
||||||
Handle<Object>(Smi::FromInt(15), isolate)),
|
handle(Smi::FromInt(15), isolate)),
|
||||||
std::make_pair("var a = 5; return { val: a, val: a + 1 }.val;",
|
std::make_pair("var a = 5; return { val: a, val: a + 1 }.val;",
|
||||||
Handle<Object>(Smi::FromInt(6), isolate)),
|
handle(Smi::FromInt(6), isolate)),
|
||||||
std::make_pair("return { func: function() { return 'test' } }.func();",
|
std::make_pair("return { func: function() { return 'test' } }.func();",
|
||||||
factory->NewStringFromStaticChars("test")),
|
factory->NewStringFromStaticChars("test")),
|
||||||
std::make_pair("return { func(a) { return a + 'st'; } }.func('te');",
|
std::make_pair("return { func(a) { return a + 'st'; } }.func('te');",
|
||||||
factory->NewStringFromStaticChars("test")),
|
factory->NewStringFromStaticChars("test")),
|
||||||
std::make_pair("return { get a() { return 22; } }.a;",
|
std::make_pair("return { get a() { return 22; } }.a;",
|
||||||
Handle<Object>(Smi::FromInt(22), isolate)),
|
handle(Smi::FromInt(22), isolate)),
|
||||||
std::make_pair("var a = { get b() { return this.x + 't'; },\n"
|
std::make_pair("var a = { get b() { return this.x + 't'; },\n"
|
||||||
" set b(val) { this.x = val + 's' } };\n"
|
" set b(val) { this.x = val + 's' } };\n"
|
||||||
"a.b = 'te';\n"
|
"a.b = 'te';\n"
|
||||||
"return a.b;",
|
"return a.b;",
|
||||||
factory->NewStringFromStaticChars("test")),
|
factory->NewStringFromStaticChars("test")),
|
||||||
std::make_pair("var a = 123; return { 1: a }[1];",
|
std::make_pair("var a = 123; return { 1: a }[1];",
|
||||||
Handle<Object>(Smi::FromInt(123), isolate)),
|
handle(Smi::FromInt(123), isolate)),
|
||||||
std::make_pair("return Object.getPrototypeOf({ __proto__: null });",
|
std::make_pair("return Object.getPrototypeOf({ __proto__: null });",
|
||||||
factory->null_value()),
|
factory->null_value()),
|
||||||
std::make_pair("var a = 'test'; return { [a]: 1 }.test;",
|
std::make_pair("var a = 'test'; return { [a]: 1 }.test;",
|
||||||
Handle<Object>(Smi::FromInt(1), isolate)),
|
handle(Smi::FromInt(1), isolate)),
|
||||||
std::make_pair("var a = 'test'; return { b: a, [a]: a + 'ing' }['test']",
|
std::make_pair("var a = 'test'; return { b: a, [a]: a + 'ing' }['test']",
|
||||||
factory->NewStringFromStaticChars("testing")),
|
factory->NewStringFromStaticChars("testing")),
|
||||||
std::make_pair("var a = 'proto_str';\n"
|
std::make_pair("var a = 'proto_str';\n"
|
||||||
@ -1785,7 +1785,7 @@ TEST(InterpreterObjectLiterals) {
|
|||||||
factory->NewStringFromStaticChars("proto_str")),
|
factory->NewStringFromStaticChars("proto_str")),
|
||||||
std::make_pair("var n = 'name';\n"
|
std::make_pair("var n = 'name';\n"
|
||||||
"return { [n]: 'val', get a() { return 987 } }['a'];",
|
"return { [n]: 'val', get a() { return 987 } }['a'];",
|
||||||
Handle<Object>(Smi::FromInt(987), isolate)),
|
handle(Smi::FromInt(987), isolate)),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < arraysize(literals); i++) {
|
for (size_t i = 0; i < arraysize(literals); i++) {
|
||||||
@ -1864,19 +1864,19 @@ TEST(InterpreterContextVariables) {
|
|||||||
|
|
||||||
std::pair<const char*, Handle<Object>> context_vars[5] = {
|
std::pair<const char*, Handle<Object>> context_vars[5] = {
|
||||||
std::make_pair("var a; (function() { a = 1; })(); return a;",
|
std::make_pair("var a; (function() { a = 1; })(); return a;",
|
||||||
Handle<Object>(Smi::FromInt(1), isolate)),
|
handle(Smi::FromInt(1), isolate)),
|
||||||
std::make_pair("var a = 10; (function() { a; })(); return a;",
|
std::make_pair("var a = 10; (function() { a; })(); return a;",
|
||||||
Handle<Object>(Smi::FromInt(10), isolate)),
|
handle(Smi::FromInt(10), isolate)),
|
||||||
std::make_pair("var a = 20; var b = 30;\n"
|
std::make_pair("var a = 20; var b = 30;\n"
|
||||||
"return (function() { return a + b; })();",
|
"return (function() { return a + b; })();",
|
||||||
Handle<Object>(Smi::FromInt(50), isolate)),
|
handle(Smi::FromInt(50), isolate)),
|
||||||
std::make_pair("'use strict'; let a = 1;\n"
|
std::make_pair("'use strict'; let a = 1;\n"
|
||||||
"{ let b = 2; return (function() { return a + b; })(); }",
|
"{ let b = 2; return (function() { return a + b; })(); }",
|
||||||
Handle<Object>(Smi::FromInt(3), isolate)),
|
handle(Smi::FromInt(3), isolate)),
|
||||||
std::make_pair("'use strict'; let a = 10;\n"
|
std::make_pair("'use strict'; let a = 10;\n"
|
||||||
"{ let b = 20; var c = function() { [a, b] };\n"
|
"{ let b = 20; var c = function() { [a, b] };\n"
|
||||||
" return a + b; }",
|
" return a + b; }",
|
||||||
Handle<Object>(Smi::FromInt(30), isolate)),
|
handle(Smi::FromInt(30), isolate)),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < arraysize(context_vars); i++) {
|
for (size_t i = 0; i < arraysize(context_vars); i++) {
|
||||||
@ -1896,11 +1896,11 @@ TEST(InterpreterContextParameters) {
|
|||||||
|
|
||||||
std::pair<const char*, Handle<Object>> context_params[3] = {
|
std::pair<const char*, Handle<Object>> context_params[3] = {
|
||||||
std::make_pair("return (function() { return arg1; })();",
|
std::make_pair("return (function() { return arg1; })();",
|
||||||
Handle<Object>(Smi::FromInt(1), isolate)),
|
handle(Smi::FromInt(1), isolate)),
|
||||||
std::make_pair("(function() { arg1 = 4; })(); return arg1;",
|
std::make_pair("(function() { arg1 = 4; })(); return arg1;",
|
||||||
Handle<Object>(Smi::FromInt(4), isolate)),
|
handle(Smi::FromInt(4), isolate)),
|
||||||
std::make_pair("(function() { arg3 = arg2 - arg1; })(); return arg3;",
|
std::make_pair("(function() { arg3 = arg2 - arg1; })(); return arg3;",
|
||||||
Handle<Object>(Smi::FromInt(1), isolate)),
|
handle(Smi::FromInt(1), isolate)),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < arraysize(context_params); i++) {
|
for (size_t i = 0; i < arraysize(context_params); i++) {
|
||||||
@ -1910,9 +1910,9 @@ TEST(InterpreterContextParameters) {
|
|||||||
auto callable =
|
auto callable =
|
||||||
tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
|
tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
|
||||||
|
|
||||||
Handle<Object> a1 = Handle<Object>(Smi::FromInt(1), isolate);
|
Handle<Object> a1 = handle(Smi::FromInt(1), isolate);
|
||||||
Handle<Object> a2 = Handle<Object>(Smi::FromInt(2), isolate);
|
Handle<Object> a2 = handle(Smi::FromInt(2), isolate);
|
||||||
Handle<Object> a3 = Handle<Object>(Smi::FromInt(3), isolate);
|
Handle<Object> a3 = handle(Smi::FromInt(3), isolate);
|
||||||
Handle<i::Object> return_value = callable(a1, a2, a3).ToHandleChecked();
|
Handle<i::Object> return_value = callable(a1, a2, a3).ToHandleChecked();
|
||||||
CHECK(return_value->SameValue(*context_params[i].second));
|
CHECK(return_value->SameValue(*context_params[i].second));
|
||||||
}
|
}
|
||||||
@ -1927,14 +1927,14 @@ TEST(InterpreterComma) {
|
|||||||
std::pair<const char*, Handle<Object>> literals[6] = {
|
std::pair<const char*, Handle<Object>> literals[6] = {
|
||||||
std::make_pair("var a; return 0, a;\n", factory->undefined_value()),
|
std::make_pair("var a; return 0, a;\n", factory->undefined_value()),
|
||||||
std::make_pair("return 'a', 2.2, 3;\n",
|
std::make_pair("return 'a', 2.2, 3;\n",
|
||||||
Handle<Object>(Smi::FromInt(3), isolate)),
|
handle(Smi::FromInt(3), isolate)),
|
||||||
std::make_pair("return 'a', 'b', 'c';\n",
|
std::make_pair("return 'a', 'b', 'c';\n",
|
||||||
factory->NewStringFromStaticChars("c")),
|
factory->NewStringFromStaticChars("c")),
|
||||||
std::make_pair("return 3.2, 2.3, 4.5;\n", factory->NewNumber(4.5)),
|
std::make_pair("return 3.2, 2.3, 4.5;\n", factory->NewNumber(4.5)),
|
||||||
std::make_pair("var a = 10; return b = a, b = b+1;\n",
|
std::make_pair("var a = 10; return b = a, b = b+1;\n",
|
||||||
Handle<Object>(Smi::FromInt(11), isolate)),
|
handle(Smi::FromInt(11), isolate)),
|
||||||
std::make_pair("var a = 10; return b = a, b = b+1, b + 10;\n",
|
std::make_pair("var a = 10; return b = a, b = b+1, b + 10;\n",
|
||||||
Handle<Object>(Smi::FromInt(21), isolate))};
|
handle(Smi::FromInt(21), isolate))};
|
||||||
|
|
||||||
for (size_t i = 0; i < arraysize(literals); i++) {
|
for (size_t i = 0; i < arraysize(literals); i++) {
|
||||||
std::string source(InterpreterTester::SourceForBody(literals[i].first));
|
std::string source(InterpreterTester::SourceForBody(literals[i].first));
|
||||||
@ -1955,7 +1955,7 @@ TEST(InterpreterLogicalOr) {
|
|||||||
std::pair<const char*, Handle<Object>> literals[5] = {
|
std::pair<const char*, Handle<Object>> literals[5] = {
|
||||||
std::make_pair("var a, b; return a || b;\n", factory->undefined_value()),
|
std::make_pair("var a, b; return a || b;\n", factory->undefined_value()),
|
||||||
std::make_pair("var a, b = 10; return a || b;\n",
|
std::make_pair("var a, b = 10; return a || b;\n",
|
||||||
Handle<Object>(Smi::FromInt(10), isolate)),
|
handle(Smi::FromInt(10), isolate)),
|
||||||
std::make_pair("var a = '0', b = 10; return a || b;\n",
|
std::make_pair("var a = '0', b = 10; return a || b;\n",
|
||||||
factory->NewStringFromStaticChars("0")),
|
factory->NewStringFromStaticChars("0")),
|
||||||
std::make_pair("return 0 || 3.2;\n", factory->NewNumber(3.2)),
|
std::make_pair("return 0 || 3.2;\n", factory->NewNumber(3.2)),
|
||||||
@ -1982,17 +1982,17 @@ TEST(InterpreterLogicalAnd) {
|
|||||||
std::make_pair("var a, b = 10; return a && b;\n",
|
std::make_pair("var a, b = 10; return a && b;\n",
|
||||||
factory->undefined_value()),
|
factory->undefined_value()),
|
||||||
std::make_pair("var a = 0, b = 10; return a && b / a;\n",
|
std::make_pair("var a = 0, b = 10; return a && b / a;\n",
|
||||||
Handle<Object>(Smi::FromInt(0), isolate)),
|
handle(Smi::FromInt(0), isolate)),
|
||||||
std::make_pair("var a = '0', b = 10; return a && b;\n",
|
std::make_pair("var a = '0', b = 10; return a && b;\n",
|
||||||
Handle<Object>(Smi::FromInt(10), isolate)),
|
handle(Smi::FromInt(10), isolate)),
|
||||||
std::make_pair("return 0.0 && 3.2;\n",
|
std::make_pair("return 0.0 && 3.2;\n",
|
||||||
Handle<Object>(Smi::FromInt(0), isolate)),
|
handle(Smi::FromInt(0), isolate)),
|
||||||
std::make_pair("return 'a' && 'b';\n",
|
std::make_pair("return 'a' && 'b';\n",
|
||||||
factory->NewStringFromStaticChars("b")),
|
factory->NewStringFromStaticChars("b")),
|
||||||
std::make_pair("return 'a' && 0 || 'b', 'c';\n",
|
std::make_pair("return 'a' && 0 || 'b', 'c';\n",
|
||||||
factory->NewStringFromStaticChars("c")),
|
factory->NewStringFromStaticChars("c")),
|
||||||
std::make_pair("var x = 1, y = 3; return x && 0 + 1 || y;\n",
|
std::make_pair("var x = 1, y = 3; return x && 0 + 1 || y;\n",
|
||||||
Handle<Object>(Smi::FromInt(1), isolate))};
|
handle(Smi::FromInt(1), isolate))};
|
||||||
|
|
||||||
for (size_t i = 0; i < arraysize(literals); i++) {
|
for (size_t i = 0; i < arraysize(literals); i++) {
|
||||||
std::string source(InterpreterTester::SourceForBody(literals[i].first));
|
std::string source(InterpreterTester::SourceForBody(literals[i].first));
|
||||||
@ -2043,7 +2043,7 @@ TEST(InterpreterThrow) {
|
|||||||
std::make_pair("throw undefined;\n",
|
std::make_pair("throw undefined;\n",
|
||||||
factory->undefined_value()),
|
factory->undefined_value()),
|
||||||
std::make_pair("throw 1;\n",
|
std::make_pair("throw 1;\n",
|
||||||
Handle<Object>(Smi::FromInt(1), isolate)),
|
handle(Smi::FromInt(1), isolate)),
|
||||||
std::make_pair("throw 'Error';\n",
|
std::make_pair("throw 'Error';\n",
|
||||||
factory->NewStringFromStaticChars("Error")),
|
factory->NewStringFromStaticChars("Error")),
|
||||||
std::make_pair("var a = true; if (a) { throw 'Error'; }\n",
|
std::make_pair("var a = true; if (a) { throw 'Error'; }\n",
|
||||||
@ -2065,3 +2065,83 @@ TEST(InterpreterThrow) {
|
|||||||
CHECK(thrown_obj->SameValue(*throws[i].second));
|
CHECK(thrown_obj->SameValue(*throws[i].second));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(InterpreterCountOperators) {
|
||||||
|
HandleAndZoneScope handles;
|
||||||
|
i::Isolate* isolate = handles.main_isolate();
|
||||||
|
i::Factory* factory = isolate->factory();
|
||||||
|
|
||||||
|
std::pair<const char*, Handle<Object>> count_ops[16] = {
|
||||||
|
std::make_pair("var a = 1; return ++a;",
|
||||||
|
handle(Smi::FromInt(2), isolate)),
|
||||||
|
std::make_pair("var a = 1; return a++;",
|
||||||
|
handle(Smi::FromInt(1), isolate)),
|
||||||
|
std::make_pair("var a = 5; return --a;",
|
||||||
|
handle(Smi::FromInt(4), isolate)),
|
||||||
|
std::make_pair("var a = 5; return a--;",
|
||||||
|
handle(Smi::FromInt(5), isolate)),
|
||||||
|
std::make_pair("var a = 5.2; return --a;",
|
||||||
|
factory->NewHeapNumber(4.2)),
|
||||||
|
std::make_pair("var a = 'string'; return ++a;",
|
||||||
|
factory->nan_value()),
|
||||||
|
std::make_pair("var a = 'string'; return a--;",
|
||||||
|
factory->nan_value()),
|
||||||
|
std::make_pair("var a = true; return ++a;",
|
||||||
|
handle(Smi::FromInt(2), isolate)),
|
||||||
|
std::make_pair("var a = false; return a--;",
|
||||||
|
handle(Smi::FromInt(0), isolate)),
|
||||||
|
std::make_pair("var a = { val: 11 }; return ++a.val;",
|
||||||
|
handle(Smi::FromInt(12), isolate)),
|
||||||
|
std::make_pair("var a = { val: 11 }; return a.val--;",
|
||||||
|
handle(Smi::FromInt(11), isolate)),
|
||||||
|
std::make_pair("var a = { val: 11 }; return ++a.val;",
|
||||||
|
handle(Smi::FromInt(12), isolate)),
|
||||||
|
std::make_pair("var name = 'val'; var a = { val: 22 }; return --a[name];",
|
||||||
|
handle(Smi::FromInt(21), isolate)),
|
||||||
|
std::make_pair("var name = 'val'; var a = { val: 22 }; return a[name]++;",
|
||||||
|
handle(Smi::FromInt(22), isolate)),
|
||||||
|
std::make_pair("var a = 1; (function() { a = 2 })(); return ++a;",
|
||||||
|
handle(Smi::FromInt(3), isolate)),
|
||||||
|
std::make_pair("var a = 1; (function() { a = 2 })(); return a--;",
|
||||||
|
handle(Smi::FromInt(2), isolate)),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arraysize(count_ops); i++) {
|
||||||
|
std::string source(InterpreterTester::SourceForBody(count_ops[i].first));
|
||||||
|
InterpreterTester tester(handles.main_isolate(), source.c_str());
|
||||||
|
auto callable = tester.GetCallable<>();
|
||||||
|
|
||||||
|
Handle<i::Object> return_value = callable().ToHandleChecked();
|
||||||
|
CHECK(return_value->SameValue(*count_ops[i].second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(InterpreterGlobalCountOperators) {
|
||||||
|
HandleAndZoneScope handles;
|
||||||
|
i::Isolate* isolate = handles.main_isolate();
|
||||||
|
|
||||||
|
std::pair<const char*, Handle<Object>> count_ops[6] = {
|
||||||
|
std::make_pair("var global = 100;function f(){ return ++global; }",
|
||||||
|
handle(Smi::FromInt(101), isolate)),
|
||||||
|
std::make_pair("var global = 100; function f(){ return --global; }",
|
||||||
|
handle(Smi::FromInt(99), isolate)),
|
||||||
|
std::make_pair("var global = 100; function f(){ return global++; }",
|
||||||
|
handle(Smi::FromInt(100), isolate)),
|
||||||
|
std::make_pair("unallocated = 200; function f(){ return ++unallocated; }",
|
||||||
|
handle(Smi::FromInt(201), isolate)),
|
||||||
|
std::make_pair("unallocated = 200; function f(){ return --unallocated; }",
|
||||||
|
handle(Smi::FromInt(199), isolate)),
|
||||||
|
std::make_pair("unallocated = 200; function f(){ return unallocated++; }",
|
||||||
|
handle(Smi::FromInt(200), isolate)),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < arraysize(count_ops); i++) {
|
||||||
|
InterpreterTester tester(handles.main_isolate(), count_ops[i].first);
|
||||||
|
auto callable = tester.GetCallable<>();
|
||||||
|
|
||||||
|
Handle<i::Object> return_value = callable().ToHandleChecked();
|
||||||
|
CHECK(return_value->SameValue(*count_ops[i].second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -94,9 +94,14 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
|||||||
.BinaryOperation(Token::Value::SAR, reg, Strength::WEAK)
|
.BinaryOperation(Token::Value::SAR, reg, Strength::WEAK)
|
||||||
.BinaryOperation(Token::Value::SHR, reg, Strength::WEAK);
|
.BinaryOperation(Token::Value::SHR, reg, Strength::WEAK);
|
||||||
|
|
||||||
|
// Emit count operatior invocations
|
||||||
|
builder.CountOperation(Token::Value::ADD, Strength::WEAK)
|
||||||
|
.CountOperation(Token::Value::SUB, Strength::WEAK);
|
||||||
|
|
||||||
// Emit unary operator invocations.
|
// Emit unary operator invocations.
|
||||||
builder.LogicalNot().TypeOf();
|
builder.LogicalNot().TypeOf();
|
||||||
|
|
||||||
|
|
||||||
// Emit new.
|
// Emit new.
|
||||||
builder.New(reg, reg, 0);
|
builder.New(reg, reg, 0);
|
||||||
|
|
||||||
@ -113,7 +118,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
|||||||
.CompareOperation(Token::Value::IN, reg, Strength::WEAK);
|
.CompareOperation(Token::Value::IN, reg, Strength::WEAK);
|
||||||
|
|
||||||
// Emit cast operator invocations.
|
// Emit cast operator invocations.
|
||||||
builder.LoadNull()
|
builder.CastAccumulatorToNumber()
|
||||||
.CastAccumulatorToBoolean()
|
.CastAccumulatorToBoolean()
|
||||||
.CastAccumulatorToName();
|
.CastAccumulatorToName();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user