From: rmcilroy Date: Thu, 27 Aug 2015 10:32:26 +0000 (-0700) Subject: [Interpreter] Add support for parameter variables. X-Git-Tag: upstream/4.7.83~637 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5d975694e4d3ecf66716cc5395d4d10c9730f9dd;p=platform%2Fupstream%2Fv8.git [Interpreter] Add support for parameter variables. Adds support for parameters to the BytecodeArrayBuilder and BytecodeGenerator. Parameters are accessed as negative interpreter registers. BUG=v8:4280 LOG=N Review URL: https://codereview.chromium.org/1303403004 Cr-Commit-Position: refs/heads/master@{#30403} --- diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc index 3902584..9186c35 100644 --- a/src/arm/builtins-arm.cc +++ b/src/arm/builtins-arm.cc @@ -1003,8 +1003,11 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { // Leave the frame (also dropping the register file). __ LeaveFrame(StackFrame::JAVA_SCRIPT); - // Drop receiver + arguments. - __ Drop(1); // TODO(rmcilroy): Get number of arguments from BytecodeArray. + + // Drop receiver + arguments and return. + __ ldr(ip, FieldMemOperand(kInterpreterBytecodeArrayRegister, + BytecodeArray::kParameterSizeOffset)); + __ add(sp, sp, ip, LeaveCC); __ Jump(lr); } diff --git a/src/arm64/builtins-arm64.cc b/src/arm64/builtins-arm64.cc index 3b568b4..3c51f50 100644 --- a/src/arm64/builtins-arm64.cc +++ b/src/arm64/builtins-arm64.cc @@ -1025,9 +1025,11 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { // Leave the frame (also dropping the register file). __ LeaveFrame(StackFrame::JAVA_SCRIPT); - // Drop receiver + arguments. - // TODO(rmcilroy): Get number of arguments from BytecodeArray. - __ Drop(1, kXRegSize); + + // Drop receiver + arguments and return. + __ Ldr(w1, FieldMemOperand(kInterpreterBytecodeArrayRegister, + BytecodeArray::kParameterSizeOffset)); + __ Drop(x1, 1); __ Ret(); } diff --git a/src/factory.cc b/src/factory.cc index 1993965..8850861 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -889,10 +889,12 @@ Handle Factory::NewByteArray(int length, PretenureFlag pretenure) { Handle Factory::NewBytecodeArray(int length, const byte* raw_bytecodes, - int frame_size) { + int frame_size, + int parameter_count) { DCHECK(0 <= length); - CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateBytecodeArray( - length, raw_bytecodes, frame_size), + CALL_HEAP_FUNCTION(isolate(), + isolate()->heap()->AllocateBytecodeArray( + length, raw_bytecodes, frame_size, parameter_count), BytecodeArray); } diff --git a/src/factory.h b/src/factory.h index aa49b99..bfca11e 100644 --- a/src/factory.h +++ b/src/factory.h @@ -288,7 +288,7 @@ class Factory final { PretenureFlag pretenure = NOT_TENURED); Handle NewBytecodeArray(int length, const byte* raw_bytecodes, - int frame_size); + int frame_size, int parameter_count); Handle NewFixedTypedArrayWithExternalPointer( int length, ExternalArrayType array_type, void* external_pointer, diff --git a/src/frames.h b/src/frames.h index fecaec6..05c0a35 100644 --- a/src/frames.h +++ b/src/frames.h @@ -174,6 +174,14 @@ class ConstructFrameConstants : public AllStatic { }; +class InterpreterFrameConstants : public AllStatic { + public: + // Register file pointer relative. + static const int kLastParamFromRegisterPointer = + StandardFrameConstants::kFixedFrameSize + kPointerSize; +}; + + // Abstract base class for all stack frames. class StackFrame BASE_EMBEDDED { public: diff --git a/src/heap/heap.cc b/src/heap/heap.cc index accae68..ca50fdd 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -2924,8 +2924,7 @@ bool Heap::CreateInitialMaps() { set_empty_byte_array(byte_array); BytecodeArray* bytecode_array; - AllocationResult allocation = - AllocateBytecodeArray(0, nullptr, kPointerSize); + AllocationResult allocation = AllocateBytecodeArray(0, nullptr, 0, 0); if (!allocation.To(&bytecode_array)) { return false; } @@ -3524,7 +3523,8 @@ AllocationResult Heap::AllocateByteArray(int length, PretenureFlag pretenure) { AllocationResult Heap::AllocateBytecodeArray(int length, const byte* const raw_bytecodes, - int frame_size) { + int frame_size, + int parameter_count) { if (length < 0 || length > BytecodeArray::kMaxLength) { v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); } @@ -3540,6 +3540,7 @@ AllocationResult Heap::AllocateBytecodeArray(int length, BytecodeArray* instance = BytecodeArray::cast(result); instance->set_length(length); instance->set_frame_size(frame_size); + instance->set_parameter_count(parameter_count); CopyBytes(instance->GetFirstBytecodeAddress(), raw_bytecodes, length); return result; diff --git a/src/heap/heap.h b/src/heap/heap.h index a529080..ea99fd8 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -1996,7 +1996,8 @@ class Heap { // Allocates a bytecode array with given contents. MUST_USE_RESULT AllocationResult - AllocateBytecodeArray(int length, const byte* raw_bytecodes, int frame_size); + AllocateBytecodeArray(int length, const byte* raw_bytecodes, int frame_size, + int parameter_count); // Copy the code and scope info part of the code object, but insert // the provided data as the relocation information. diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index 1b25af7..db3c6ef 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -752,9 +752,14 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { // Leave the frame (also dropping the register file). __ leave(); - // Return droping receiver + arguments. - // TODO(rmcilroy): Get number of arguments from BytecodeArray. - __ Ret(1 * kPointerSize, ecx); + + // Drop receiver + arguments and return. + __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister, + BytecodeArray::kParameterSizeOffset)); + __ pop(ecx); + __ add(esp, ebx); + __ push(ecx); + __ ret(0); } diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc index bb1c69b..ebab9f1 100644 --- a/src/interpreter/bytecode-array-builder.cc +++ b/src/interpreter/bytecode-array-builder.cc @@ -11,6 +11,7 @@ namespace interpreter { BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate) : isolate_(isolate), bytecode_generated_(false), + parameter_count_(-1), local_register_count_(-1), temporary_register_count_(0), temporary_register_next_(0) {} @@ -25,14 +26,30 @@ void BytecodeArrayBuilder::set_locals_count(int number_of_locals) { int BytecodeArrayBuilder::locals_count() const { return local_register_count_; } +void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) { + parameter_count_ = number_of_parameters; +} + + +int BytecodeArrayBuilder::parameter_count() const { return parameter_count_; } + + +Register BytecodeArrayBuilder::Parameter(int param_index) { + DCHECK_GE(param_index, 0); + DCHECK_LT(param_index, parameter_count_); + return Register(kLastParamRegisterIndex - parameter_count_ + param_index + 1); +} + + Handle BytecodeArrayBuilder::ToBytecodeArray() { DCHECK_EQ(bytecode_generated_, false); + DCHECK_GE(parameter_count_, 0); DCHECK_GE(local_register_count_, 0); int bytecode_size = static_cast(bytecodes_.size()); int register_count = local_register_count_ + temporary_register_count_; int frame_size = register_count * kPointerSize; Handle output = isolate_->factory()->NewBytecodeArray( - bytecode_size, &bytecodes_.front(), frame_size); + bytecode_size, &bytecodes_.front(), frame_size, parameter_count_); bytecode_generated_ = true; return output; } @@ -135,9 +152,12 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, return false; case OperandType::kImm8: return true; - case OperandType::kReg: - return Register::FromOperand(operand_value).index() < - temporary_register_next_; + case OperandType::kReg: { + int reg_index = Register::FromOperand(operand_value).index(); + return (reg_index >= 0 && reg_index < temporary_register_next_) || + (reg_index <= kLastParamRegisterIndex && + reg_index > kLastParamRegisterIndex - parameter_count_); + } } UNREACHABLE(); return false; diff --git a/src/interpreter/bytecode-array-builder.h b/src/interpreter/bytecode-array-builder.h index c4ab816..fda32e6 100644 --- a/src/interpreter/bytecode-array-builder.h +++ b/src/interpreter/bytecode-array-builder.h @@ -8,6 +8,7 @@ #include #include "src/ast.h" +#include "src/frames.h" #include "src/interpreter/bytecodes.h" namespace v8 { @@ -24,10 +25,16 @@ class BytecodeArrayBuilder { explicit BytecodeArrayBuilder(Isolate* isolate); Handle ToBytecodeArray(); + // Set number of parameters expected by function. + void set_parameter_count(int number_of_params); + int parameter_count() const; + // Set number of locals required for bytecode array. void set_locals_count(int number_of_locals); int locals_count() const; + Register Parameter(int parameter_index); + // Constant loads to accumulator. BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value); BytecodeArrayBuilder& LoadUndefined(); @@ -47,6 +54,9 @@ class BytecodeArrayBuilder { BytecodeArrayBuilder& Return(); private: + static const int kLastParamRegisterIndex = + -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize; + static Bytecode BytecodeForBinaryOperation(Token::Value op); void Output(Bytecode bytecode, uint8_t r0, uint8_t r1, uint8_t r2); @@ -64,6 +74,7 @@ class BytecodeArrayBuilder { std::vector bytecodes_; bool bytecode_generated_; + int parameter_count_; int local_register_count_; int temporary_register_count_; int temporary_register_next_; @@ -72,17 +83,20 @@ class BytecodeArrayBuilder { DISALLOW_IMPLICIT_CONSTRUCTORS(BytecodeArrayBuilder); }; -// An interpreter register which is located in the function's regsiter file +// An interpreter register which is located in the function's register file // in its stack-frame. class Register { public: static const int kMaxRegisterIndex = 128; + static const int kMinRegisterIndex = -127; explicit Register(int index) : index_(index) { DCHECK_LE(index_, kMaxRegisterIndex); + DCHECK_GE(index_, kMinRegisterIndex); } int index() { return index_; } + uint8_t ToOperand() { return static_cast(-index_); } static Register FromOperand(uint8_t operand) { return Register(-static_cast(operand)); diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc index 50f27bd..93d96ed 100644 --- a/src/interpreter/bytecode-generator.cc +++ b/src/interpreter/bytecode-generator.cc @@ -30,6 +30,7 @@ Handle BytecodeGenerator::MakeBytecode(CompilationInfo* info) { // This a temporary guard (oth). DCHECK(scope()->is_function_scope()); + builder().set_parameter_count(info->num_parameters_including_this()); builder().set_locals_count(scope()->num_stack_slots()); // Visit implicit declaration of the function name. @@ -72,8 +73,6 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { UNIMPLEMENTED(); break; case VariableLocation::PARAMETER: - UNIMPLEMENTED(); - break; case VariableLocation::LOCAL: // Details stored in scope, i.e. variable index. break; @@ -248,9 +247,15 @@ void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { builder().LoadAccumulatorWithRegister(source); break; } + case VariableLocation::PARAMETER: { + // The parameter indices are shifted by 1 (receiver is variable + // index -1 but is parameter index 0 in BytecodeArrayBuilder). + Register source(builder().Parameter(variable->index() + 1)); + builder().LoadAccumulatorWithRegister(source); + break; + } case VariableLocation::GLOBAL: case VariableLocation::UNALLOCATED: - case VariableLocation::PARAMETER: case VariableLocation::CONTEXT: case VariableLocation::LOOKUP: UNIMPLEMENTED(); diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc index a05c2e4..f642660 100644 --- a/src/mips/builtins-mips.cc +++ b/src/mips/builtins-mips.cc @@ -8,7 +8,6 @@ #include "src/debug/debug.h" #include "src/deoptimizer.h" #include "src/full-codegen/full-codegen.h" -#include "src/interpreter/bytecodes.h" #include "src/runtime/runtime.h" @@ -996,8 +995,11 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { // Leave the frame (also dropping the register file). __ LeaveFrame(StackFrame::JAVA_SCRIPT); - // Drop receiver + arguments. - __ Drop(1); // TODO(rmcilroy): Get number of arguments from BytecodeArray. + + // Drop receiver + arguments and return. + __ lw(at, FieldMemOperand(kInterpreterBytecodeArrayRegister, + BytecodeArray::kParameterSizeOffset)); + __ Addu(sp, sp, at); __ Jump(ra); } diff --git a/src/mips64/builtins-mips64.cc b/src/mips64/builtins-mips64.cc index 85ba4cb..1fc04a4 100644 --- a/src/mips64/builtins-mips64.cc +++ b/src/mips64/builtins-mips64.cc @@ -993,8 +993,11 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { // Leave the frame (also dropping the register file). __ LeaveFrame(StackFrame::JAVA_SCRIPT); - // Drop receiver + arguments. - __ Drop(1); // TODO(rmcilroy): Get number of arguments from BytecodeArray. + + // Drop receiver + arguments and return. + __ lw(at, FieldMemOperand(kInterpreterBytecodeArrayRegister, + BytecodeArray::kParameterSizeOffset)); + __ Daddu(sp, sp, at); __ Jump(ra); } diff --git a/src/objects-inl.h b/src/objects-inl.h index d61f494..506e064 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -4058,6 +4058,22 @@ int BytecodeArray::frame_size() const { } +void BytecodeArray::set_parameter_count(int number_of_parameters) { + DCHECK_GE(number_of_parameters, 0); + // Parameter count is stored as the size on stack of the parameters to allow + // it to be used directly by generated code. + WRITE_INT_FIELD(this, kParameterSizeOffset, + (number_of_parameters << kPointerSizeLog2)); +} + + +int BytecodeArray::parameter_count() const { + // Parameter count is stored as the size on stack of the parameters to allow + // it to be used directly by generated code. + return READ_INT_FIELD(this, kParameterSizeOffset) >> kPointerSizeLog2; +} + + Address BytecodeArray::GetFirstBytecodeAddress() { return reinterpret_cast
(this) - kHeapObjectTag + kHeaderSize; } diff --git a/src/objects.cc b/src/objects.cc index 26d6945..0430f2a 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -11585,6 +11585,7 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT void BytecodeArray::Disassemble(std::ostream& os) { + os << "Parameter count " << parameter_count() << "\n"; os << "Frame size " << frame_size() << "\n"; Vector buf = Vector::New(50); diff --git a/src/objects.h b/src/objects.h index ff226e5..f45bda2 100644 --- a/src/objects.h +++ b/src/objects.h @@ -4112,9 +4112,13 @@ class BytecodeArray : public FixedArrayBase { // Returns data start address. inline Address GetFirstBytecodeAddress(); - // Accessors for frame size and the number of locals + // Accessors for frame size. inline int frame_size() const; - inline void set_frame_size(int value); + inline void set_frame_size(int frame_size); + + // Accessors for parameter count (including implicit 'this' receiver). + inline int parameter_count() const; + inline void set_parameter_count(int number_of_parameters); DECLARE_CAST(BytecodeArray) @@ -4128,7 +4132,8 @@ class BytecodeArray : public FixedArrayBase { // Layout description. static const int kFrameSizeOffset = FixedArrayBase::kHeaderSize; - static const int kHeaderSize = kFrameSizeOffset + kIntSize; + static const int kParameterSizeOffset = kFrameSizeOffset + kIntSize; + static const int kHeaderSize = kParameterSizeOffset + kIntSize; static const int kAlignedSize = OBJECT_POINTER_ALIGN(kHeaderSize); diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc index a68238a..29f4732 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -802,9 +802,14 @@ void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { // Leave the frame (also dropping the register file). __ leave(); - // Return droping receiver + arguments. - // TODO(rmcilroy): Get number of arguments from BytecodeArray. - __ Ret(1 * kPointerSize, rcx); + + // Drop receiver + arguments and return. + __ movl(rbx, FieldOperand(kInterpreterBytecodeArrayRegister, + BytecodeArray::kParameterSizeOffset)); + __ PopReturnAddressTo(rcx); + __ addp(rsp, rbx); + __ PushReturnAddressFrom(rcx); + __ ret(0); } diff --git a/test/cctest/interpreter/test-bytecode-generator.cc b/test/cctest/interpreter/test-bytecode-generator.cc index deb6c97..16dc3ee 100644 --- a/test/cctest/interpreter/test-bytecode-generator.cc +++ b/test/cctest/interpreter/test-bytecode-generator.cc @@ -15,7 +15,7 @@ namespace interpreter { class BytecodeGeneratorHelper { public: - const char* kFunctionName = "my_function"; + const char* kFunctionName = "f"; BytecodeGeneratorHelper() { i::FLAG_ignition = true; @@ -40,6 +40,12 @@ class BytecodeGeneratorHelper { kFunctionName); return MakeBytecode(program.start(), kFunctionName); } + + Handle MakeBytecodeForFunction(const char* function) { + ScopedVector program(1024); + SNPrintF(program, "%s\n%s();", function, kFunctionName); + return MakeBytecode(program.start(), kFunctionName); + } }; @@ -47,6 +53,7 @@ class BytecodeGeneratorHelper { struct ExpectedSnippet { const char* body; int frame_size; + int parameter_count; int bytecode_length; const uint8_t bytecode[16]; }; @@ -54,8 +61,8 @@ struct ExpectedSnippet { // Helper macros for handcrafting bytecode sequences. #define B(x) static_cast(Bytecode::k##x) -#define U8(x) static_cast(x & 0xff) -#define R(x) static_cast(-x & 0xff) +#define U8(x) static_cast((x) & 0xff) +#define R(x) static_cast(-(x) & 0xff) TEST(PrimitiveReturnStatements) { @@ -63,15 +70,15 @@ TEST(PrimitiveReturnStatements) { BytecodeGeneratorHelper helper; ExpectedSnippet snippets[] = { - {"return;", 0, 2, {B(LdaUndefined), B(Return)}}, - {"return null;", 0, 2, {B(LdaNull), B(Return)}}, - {"return true;", 0, 2, {B(LdaTrue), B(Return)}}, - {"return false;", 0, 2, {B(LdaFalse), B(Return)}}, - {"return 0;", 0, 2, {B(LdaZero), B(Return)}}, - {"return +1;", 0, 3, {B(LdaSmi8), U8(1), B(Return)}}, - {"return -1;", 0, 3, {B(LdaSmi8), U8(-1), B(Return)}}, - {"return +127;", 0, 3, {B(LdaSmi8), U8(127), B(Return)}}, - {"return -128;", 0, 3, {B(LdaSmi8), U8(-128), B(Return)}}, + {"return;", 0, 1, 2, {B(LdaUndefined), B(Return)}}, + {"return null;", 0, 1, 2, {B(LdaNull), B(Return)}}, + {"return true;", 0, 1, 2, {B(LdaTrue), B(Return)}}, + {"return false;", 0, 1, 2, {B(LdaFalse), B(Return)}}, + {"return 0;", 0, 1, 2, {B(LdaZero), B(Return)}}, + {"return +1;", 0, 1, 3, {B(LdaSmi8), U8(1), B(Return)}}, + {"return -1;", 0, 1, 3, {B(LdaSmi8), U8(-1), B(Return)}}, + {"return +127;", 0, 1, 3, {B(LdaSmi8), U8(127), B(Return)}}, + {"return -128;", 0, 1, 3, {B(LdaSmi8), U8(-128), B(Return)}}, }; size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); @@ -79,6 +86,7 @@ TEST(PrimitiveReturnStatements) { Handle ba = helper.MakeBytecodeForFunctionBody(snippets[i].body); 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())); @@ -93,6 +101,7 @@ TEST(PrimitiveExpressions) { ExpectedSnippet snippets[] = { {"var x = 0; return x;", kPointerSize, + 1, 6, { B(LdaZero), // @@ -102,6 +111,7 @@ TEST(PrimitiveExpressions) { }}, {"var x = 0; return x + 3;", 2 * kPointerSize, + 1, 12, { B(LdaZero), // @@ -118,6 +128,38 @@ TEST(PrimitiveExpressions) { Handle ba = helper.MakeBytecodeForFunctionBody(snippets[i].body); 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())); + } +} + + +TEST(Parameters) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + int last_param_index = + -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize; + ExpectedSnippet snippets[] = { + {"function f() { return this; }", + 0, 1, 3, {B(Ldar), R(last_param_index), B(Return)}}, + {"function f(arg1) { return arg1; }", + 0, 2, 3, {B(Ldar), R(last_param_index), B(Return)}}, + {"function f(arg1) { return this; }", + 0, 2, 3, {B(Ldar), R(last_param_index - 1), B(Return)}}, + {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return arg4; }", + 0, 8, 3, {B(Ldar), R(last_param_index - 3), B(Return)}}, + {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return this; }", + 0, 8, 3, {B(Ldar), R(last_param_index - 7), B(Return)}} + }; + + size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); + for (size_t i = 0; i < num_snippets; i++) { + Handle ba = helper.MakeBytecodeForFunction(snippets[i].body); + 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())); diff --git a/test/cctest/interpreter/test-interpreter.cc b/test/cctest/interpreter/test-interpreter.cc index 2c55885..26deea6 100644 --- a/test/cctest/interpreter/test-interpreter.cc +++ b/test/cctest/interpreter/test-interpreter.cc @@ -14,16 +14,35 @@ namespace v8 { namespace internal { namespace interpreter { + +static MaybeHandle CallInterpreter(Isolate* isolate, + Handle function) { + return Execution::Call(isolate, function, + isolate->factory()->undefined_value(), 0, nullptr, + false); +} + + +template +static MaybeHandle CallInterpreter(Isolate* isolate, + Handle function, + A... args) { + Handle argv[] = { args... }; + return Execution::Call(isolate, function, + isolate->factory()->undefined_value(), sizeof...(args), + argv, false); +} + + +template class InterpreterCallable { public: InterpreterCallable(Isolate* isolate, Handle function) : isolate_(isolate), function_(function) {} virtual ~InterpreterCallable() {} - MaybeHandle operator()() { - return Execution::Call(isolate_, function_, - isolate_->factory()->undefined_value(), 0, nullptr, - false); + MaybeHandle operator()(A... args) { + return CallInterpreter(isolate_, function_, args...); } private: @@ -31,30 +50,39 @@ class InterpreterCallable { Handle function_; }; + class InterpreterTester { public: InterpreterTester(Isolate* isolate, Handle bytecode) - : isolate_(isolate), function_(GetBytecodeFunction(isolate, bytecode)) { + : isolate_(isolate), bytecode_(bytecode) { i::FLAG_ignition = true; // Ensure handler table is generated. isolate->interpreter()->Initialize(); } virtual ~InterpreterTester() {} - InterpreterCallable GetCallable() { - return InterpreterCallable(isolate_, function_); + template + InterpreterCallable GetCallable() { + return InterpreterCallable(isolate_, GetBytecodeFunction()); } private: Isolate* isolate_; - Handle function_; + Handle bytecode_; + + template + Handle GetBytecodeFunction() { + int arg_count = sizeof...(A); + std::string function_text("(function("); + for (int i = 0; i < arg_count; i++) { + function_text += i == 0 ? "a" : ", a"; + } + function_text += "){})"; - static Handle GetBytecodeFunction( - Isolate* isolate, Handle bytecode_array) { Handle function = v8::Utils::OpenHandle( - *v8::Handle::Cast(CompileRun("(function(){})"))); - function->ReplaceCode(*isolate->builtins()->InterpreterEntryTrampoline()); - function->shared()->set_function_data(*bytecode_array); + *v8::Handle::Cast(CompileRun(function_text.c_str()))); + function->ReplaceCode(*isolate_->builtins()->InterpreterEntryTrampoline()); + function->shared()->set_function_data(*bytecode_); return function; } @@ -72,127 +100,135 @@ using v8::internal::Smi; using v8::internal::Token; using namespace v8::internal::interpreter; -TEST(TestInterpreterReturn) { +TEST(InterpreterReturn) { InitializedHandleScope handles; Handle undefined_value = handles.main_isolate()->factory()->undefined_value(); BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(0); + builder.set_parameter_count(1); builder.Return(); Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK(return_val.is_identical_to(undefined_value)); } -TEST(TestInterpreterLoadUndefined) { +TEST(InterpreterLoadUndefined) { InitializedHandleScope handles; Handle undefined_value = handles.main_isolate()->factory()->undefined_value(); BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(0); + builder.set_parameter_count(1); builder.LoadUndefined().Return(); Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK(return_val.is_identical_to(undefined_value)); } -TEST(TestInterpreterLoadNull) { +TEST(InterpreterLoadNull) { InitializedHandleScope handles; Handle null_value = handles.main_isolate()->factory()->null_value(); BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(0); + builder.set_parameter_count(1); builder.LoadNull().Return(); Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK(return_val.is_identical_to(null_value)); } -TEST(TestInterpreterLoadTheHole) { +TEST(InterpreterLoadTheHole) { InitializedHandleScope handles; Handle the_hole_value = handles.main_isolate()->factory()->the_hole_value(); BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(0); + builder.set_parameter_count(1); builder.LoadTheHole().Return(); Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK(return_val.is_identical_to(the_hole_value)); } -TEST(TestInterpreterLoadTrue) { +TEST(InterpreterLoadTrue) { InitializedHandleScope handles; Handle true_value = handles.main_isolate()->factory()->true_value(); BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(0); + builder.set_parameter_count(1); builder.LoadTrue().Return(); Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK(return_val.is_identical_to(true_value)); } -TEST(TestInterpreterLoadFalse) { +TEST(InterpreterLoadFalse) { InitializedHandleScope handles; Handle false_value = handles.main_isolate()->factory()->false_value(); BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(0); + builder.set_parameter_count(1); builder.LoadFalse().Return(); Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK(return_val.is_identical_to(false_value)); } -TEST(TestInterpreterLoadLiteral) { +TEST(InterpreterLoadLiteral) { InitializedHandleScope handles; for (int i = -128; i < 128; i++) { BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(0); + builder.set_parameter_count(1); builder.LoadLiteral(Smi::FromInt(i)).Return(); Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(i)); } } -TEST(TestInterpreterLoadStoreRegisters) { +TEST(InterpreterLoadStoreRegisters) { InitializedHandleScope handles; Handle true_value = handles.main_isolate()->factory()->true_value(); for (int i = 0; i <= Register::kMaxRegisterIndex; i++) { BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(i + 1); + builder.set_parameter_count(1); Register reg(i); builder.LoadTrue() .StoreAccumulatorInRegister(reg) @@ -202,19 +238,20 @@ TEST(TestInterpreterLoadStoreRegisters) { Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK(return_val.is_identical_to(true_value)); } } -TEST(TestInterpreterAdd) { +TEST(InterpreterAdd) { InitializedHandleScope handles; // TODO(rmcilroy): Do add tests for heap numbers and strings once we support // them. BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(1); + builder.set_parameter_count(1); Register reg(0); builder.LoadLiteral(Smi::FromInt(1)) .StoreAccumulatorInRegister(reg) @@ -224,17 +261,18 @@ TEST(TestInterpreterAdd) { Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3)); } -TEST(TestInterpreterSub) { +TEST(InterpreterSub) { InitializedHandleScope handles; // TODO(rmcilroy): Do add tests for heap numbers once we support them. BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(1); + builder.set_parameter_count(1); Register reg(0); builder.LoadLiteral(Smi::FromInt(5)) .StoreAccumulatorInRegister(reg) @@ -244,17 +282,18 @@ TEST(TestInterpreterSub) { Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(-26)); } -TEST(TestInterpreterMul) { +TEST(InterpreterMul) { InitializedHandleScope handles; // TODO(rmcilroy): Do add tests for heap numbers once we support them. BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(1); + builder.set_parameter_count(1); Register reg(0); builder.LoadLiteral(Smi::FromInt(111)) .StoreAccumulatorInRegister(reg) @@ -264,17 +303,18 @@ TEST(TestInterpreterMul) { Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(666)); } -TEST(TestInterpreterDiv) { +TEST(InterpreterDiv) { InitializedHandleScope handles; // TODO(rmcilroy): Do add tests for heap numbers once we support them. BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(1); + builder.set_parameter_count(1); Register reg(0); builder.LoadLiteral(Smi::FromInt(-20)) .StoreAccumulatorInRegister(reg) @@ -284,17 +324,18 @@ TEST(TestInterpreterDiv) { Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(-4)); } -TEST(TestInterpreterMod) { +TEST(InterpreterMod) { InitializedHandleScope handles; // TODO(rmcilroy): Do add tests for heap numbers once we support them. BytecodeArrayBuilder builder(handles.main_isolate()); builder.set_locals_count(1); + builder.set_parameter_count(1); Register reg(0); builder.LoadLiteral(Smi::FromInt(121)) .StoreAccumulatorInRegister(reg) @@ -304,7 +345,66 @@ TEST(TestInterpreterMod) { Handle bytecode_array = builder.ToBytecodeArray(); InterpreterTester tester(handles.main_isolate(), bytecode_array); - InterpreterCallable callable(tester.GetCallable()); + auto callable = tester.GetCallable<>(); Handle return_val = callable().ToHandleChecked(); CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(21)); } + + +TEST(InterpreterParameter1) { + InitializedHandleScope handles; + BytecodeArrayBuilder builder(handles.main_isolate()); + builder.set_locals_count(1); + builder.set_parameter_count(1); + builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return(); + Handle bytecode_array = builder.ToBytecodeArray(); + + InterpreterTester tester(handles.main_isolate(), bytecode_array); + auto callable = tester.GetCallable>(); + + // Check for heap objects. + Handle true_value = handles.main_isolate()->factory()->true_value(); + Handle return_val = callable(true_value).ToHandleChecked(); + CHECK(return_val.is_identical_to(true_value)); + + // Check for Smis. + return_val = callable(Handle(Smi::FromInt(3), handles.main_isolate())) + .ToHandleChecked(); + CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3)); +} + + +TEST(InterpreterParameter8) { + InitializedHandleScope handles; + BytecodeArrayBuilder builder(handles.main_isolate()); + builder.set_locals_count(1); + builder.set_parameter_count(8); + builder.LoadAccumulatorWithRegister(builder.Parameter(0)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(1)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(2)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(3)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(4)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(5)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(6)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(7)) + .Return(); + Handle bytecode_array = builder.ToBytecodeArray(); + + InterpreterTester tester(handles.main_isolate(), bytecode_array); + typedef Handle H; + auto callable = tester.GetCallable(); + + Handle arg1 = Handle(Smi::FromInt(1), handles.main_isolate()); + Handle arg2 = Handle(Smi::FromInt(2), handles.main_isolate()); + Handle arg3 = Handle(Smi::FromInt(3), handles.main_isolate()); + Handle arg4 = Handle(Smi::FromInt(4), handles.main_isolate()); + Handle arg5 = Handle(Smi::FromInt(5), handles.main_isolate()); + Handle arg6 = Handle(Smi::FromInt(6), handles.main_isolate()); + Handle arg7 = Handle(Smi::FromInt(7), handles.main_isolate()); + Handle arg8 = Handle(Smi::FromInt(8), handles.main_isolate()); + // Check for Smis. + Handle return_val = + callable(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + .ToHandleChecked(); + CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(36)); +} diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 4d21031..d7193dc 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -711,6 +711,7 @@ TEST(BytecodeArray) { static const uint8_t kRawBytes[] = {0xc3, 0x7e, 0xa5, 0x5a}; static const int kRawBytesSize = sizeof(kRawBytes); static const int kFrameSize = 32; + static const int kParameterCount = 2; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); @@ -719,12 +720,13 @@ TEST(BytecodeArray) { HandleScope scope(isolate); // Allocate and initialize BytecodeArray - Handle array = - factory->NewBytecodeArray(kRawBytesSize, kRawBytes, kFrameSize); + Handle array = factory->NewBytecodeArray( + kRawBytesSize, kRawBytes, kFrameSize, kParameterCount); CHECK(array->IsBytecodeArray()); CHECK_EQ(array->length(), (int)sizeof(kRawBytes)); CHECK_EQ(array->frame_size(), kFrameSize); + CHECK_EQ(array->parameter_count(), kParameterCount); CHECK_LE(array->address(), array->GetFirstBytecodeAddress()); CHECK_GE(array->address() + array->BytecodeArraySize(), array->GetFirstBytecodeAddress() + array->length()); diff --git a/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/test/unittests/interpreter/bytecode-array-builder-unittest.cc index 72af0c4..9b4d3ab 100644 --- a/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -22,6 +22,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { BytecodeArrayBuilder builder(isolate()); builder.set_locals_count(1); + builder.set_parameter_count(0); CHECK_EQ(builder.locals_count(), 1); // Emit constant loads. @@ -79,6 +80,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { for (int locals = 0; locals < 5; locals++) { for (int temps = 0; temps < 3; temps++) { BytecodeArrayBuilder builder(isolate()); + builder.set_parameter_count(0); builder.set_locals_count(locals); builder.Return(); @@ -97,6 +99,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) { BytecodeArrayBuilder builder(isolate()); + builder.set_parameter_count(0); builder.set_locals_count(0); builder.Return(); @@ -133,6 +136,17 @@ TEST_F(BytecodeArrayBuilderTest, RegisterValues) { CHECK_EQ(actual_index, index); } + +TEST_F(BytecodeArrayBuilderTest, Parameters) { + BytecodeArrayBuilder builder(isolate()); + builder.set_parameter_count(10); + builder.set_locals_count(0); + + Register param0(builder.Parameter(0)); + Register param9(builder.Parameter(9)); + CHECK_EQ(param9.index() - param0.index(), 9); +} + } // namespace interpreter } // namespace internal } // namespace v8