// 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);
}
// 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();
}
Handle<BytecodeArray> 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);
}
PretenureFlag pretenure = NOT_TENURED);
Handle<BytecodeArray> NewBytecodeArray(int length, const byte* raw_bytecodes,
- int frame_size);
+ int frame_size, int parameter_count);
Handle<FixedTypedArrayBase> NewFixedTypedArrayWithExternalPointer(
int length, ExternalArrayType array_type, void* external_pointer,
};
+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:
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;
}
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);
}
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;
// 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.
// 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);
}
BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate)
: isolate_(isolate),
bytecode_generated_(false),
+ parameter_count_(-1),
local_register_count_(-1),
temporary_register_count_(0),
temporary_register_next_(0) {}
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<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
DCHECK_EQ(bytecode_generated_, false);
+ DCHECK_GE(parameter_count_, 0);
DCHECK_GE(local_register_count_, 0);
int bytecode_size = static_cast<int>(bytecodes_.size());
int register_count = local_register_count_ + temporary_register_count_;
int frame_size = register_count * kPointerSize;
Handle<BytecodeArray> output = isolate_->factory()->NewBytecodeArray(
- bytecode_size, &bytecodes_.front(), frame_size);
+ bytecode_size, &bytecodes_.front(), frame_size, parameter_count_);
bytecode_generated_ = true;
return output;
}
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;
#include <vector>
#include "src/ast.h"
+#include "src/frames.h"
#include "src/interpreter/bytecodes.h"
namespace v8 {
explicit BytecodeArrayBuilder(Isolate* isolate);
Handle<BytecodeArray> 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();
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);
std::vector<uint8_t> bytecodes_;
bool bytecode_generated_;
+ int parameter_count_;
int local_register_count_;
int temporary_register_count_;
int temporary_register_next_;
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<uint8_t>(-index_); }
static Register FromOperand(uint8_t operand) {
return Register(-static_cast<int8_t>(operand));
// 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.
UNIMPLEMENTED();
break;
case VariableLocation::PARAMETER:
- UNIMPLEMENTED();
- break;
case VariableLocation::LOCAL:
// Details stored in scope, i.e. variable index.
break;
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();
#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"
// 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);
}
// 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);
}
}
+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<Address>(this) - kHeapObjectTag + kHeaderSize;
}
void BytecodeArray::Disassemble(std::ostream& os) {
+ os << "Parameter count " << parameter_count() << "\n";
os << "Frame size " << frame_size() << "\n";
Vector<char> buf = Vector<char>::New(50);
// 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)
// 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);
// 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);
}
class BytecodeGeneratorHelper {
public:
- const char* kFunctionName = "my_function";
+ const char* kFunctionName = "f";
BytecodeGeneratorHelper() {
i::FLAG_ignition = true;
kFunctionName);
return MakeBytecode(program.start(), kFunctionName);
}
+
+ Handle<BytecodeArray> MakeBytecodeForFunction(const char* function) {
+ ScopedVector<char> program(1024);
+ SNPrintF(program, "%s\n%s();", function, kFunctionName);
+ return MakeBytecode(program.start(), kFunctionName);
+ }
};
struct ExpectedSnippet {
const char* body;
int frame_size;
+ int parameter_count;
int bytecode_length;
const uint8_t bytecode[16];
};
// Helper macros for handcrafting bytecode sequences.
#define B(x) static_cast<uint8_t>(Bytecode::k##x)
-#define U8(x) static_cast<uint8_t>(x & 0xff)
-#define R(x) static_cast<uint8_t>(-x & 0xff)
+#define U8(x) static_cast<uint8_t>((x) & 0xff)
+#define R(x) static_cast<uint8_t>(-(x) & 0xff)
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]);
Handle<BytecodeArray> 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()));
ExpectedSnippet snippets[] = {
{"var x = 0; return x;",
kPointerSize,
+ 1,
6,
{
B(LdaZero), //
}},
{"var x = 0; return x + 3;",
2 * kPointerSize,
+ 1,
12,
{
B(LdaZero), //
Handle<BytecodeArray> 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<BytecodeArray> 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()));
namespace internal {
namespace interpreter {
+
+static MaybeHandle<Object> CallInterpreter(Isolate* isolate,
+ Handle<JSFunction> function) {
+ return Execution::Call(isolate, function,
+ isolate->factory()->undefined_value(), 0, nullptr,
+ false);
+}
+
+
+template <class... A>
+static MaybeHandle<Object> CallInterpreter(Isolate* isolate,
+ Handle<JSFunction> function,
+ A... args) {
+ Handle<Object> argv[] = { args... };
+ return Execution::Call(isolate, function,
+ isolate->factory()->undefined_value(), sizeof...(args),
+ argv, false);
+}
+
+
+template <class... A>
class InterpreterCallable {
public:
InterpreterCallable(Isolate* isolate, Handle<JSFunction> function)
: isolate_(isolate), function_(function) {}
virtual ~InterpreterCallable() {}
- MaybeHandle<Object> operator()() {
- return Execution::Call(isolate_, function_,
- isolate_->factory()->undefined_value(), 0, nullptr,
- false);
+ MaybeHandle<Object> operator()(A... args) {
+ return CallInterpreter(isolate_, function_, args...);
}
private:
Handle<JSFunction> function_;
};
+
class InterpreterTester {
public:
InterpreterTester(Isolate* isolate, Handle<BytecodeArray> 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 <class... A>
+ InterpreterCallable<A...> GetCallable() {
+ return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>());
}
private:
Isolate* isolate_;
- Handle<JSFunction> function_;
+ Handle<BytecodeArray> bytecode_;
+
+ template <class... A>
+ Handle<JSFunction> 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<JSFunction> GetBytecodeFunction(
- Isolate* isolate, Handle<BytecodeArray> bytecode_array) {
Handle<JSFunction> function = v8::Utils::OpenHandle(
- *v8::Handle<v8::Function>::Cast(CompileRun("(function(){})")));
- function->ReplaceCode(*isolate->builtins()->InterpreterEntryTrampoline());
- function->shared()->set_function_data(*bytecode_array);
+ *v8::Handle<v8::Function>::Cast(CompileRun(function_text.c_str())));
+ function->ReplaceCode(*isolate_->builtins()->InterpreterEntryTrampoline());
+ function->shared()->set_function_data(*bytecode_);
return function;
}
using v8::internal::Token;
using namespace v8::internal::interpreter;
-TEST(TestInterpreterReturn) {
+TEST(InterpreterReturn) {
InitializedHandleScope handles;
Handle<Object> 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<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(undefined_value));
}
-TEST(TestInterpreterLoadUndefined) {
+TEST(InterpreterLoadUndefined) {
InitializedHandleScope handles;
Handle<Object> 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<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(undefined_value));
}
-TEST(TestInterpreterLoadNull) {
+TEST(InterpreterLoadNull) {
InitializedHandleScope handles;
Handle<Object> 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<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(null_value));
}
-TEST(TestInterpreterLoadTheHole) {
+TEST(InterpreterLoadTheHole) {
InitializedHandleScope handles;
Handle<Object> 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<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(the_hole_value));
}
-TEST(TestInterpreterLoadTrue) {
+TEST(InterpreterLoadTrue) {
InitializedHandleScope handles;
Handle<Object> 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<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> return_val = callable().ToHandleChecked();
CHECK(return_val.is_identical_to(true_value));
}
-TEST(TestInterpreterLoadFalse) {
+TEST(InterpreterLoadFalse) {
InitializedHandleScope handles;
Handle<Object> 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<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> 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<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> return_val = callable().ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(i));
}
}
-TEST(TestInterpreterLoadStoreRegisters) {
+TEST(InterpreterLoadStoreRegisters) {
InitializedHandleScope handles;
Handle<Object> 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)
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> 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)
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> 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)
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> 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)
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> 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)
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> 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)
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
InterpreterTester tester(handles.main_isolate(), bytecode_array);
- InterpreterCallable callable(tester.GetCallable());
+ auto callable = tester.GetCallable<>();
Handle<Object> 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<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
+
+ InterpreterTester tester(handles.main_isolate(), bytecode_array);
+ auto callable = tester.GetCallable<Handle<Object>>();
+
+ // Check for heap objects.
+ Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
+ Handle<Object> return_val = callable(true_value).ToHandleChecked();
+ CHECK(return_val.is_identical_to(true_value));
+
+ // Check for Smis.
+ return_val = callable(Handle<Smi>(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<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
+
+ InterpreterTester tester(handles.main_isolate(), bytecode_array);
+ typedef Handle<Object> H;
+ auto callable = tester.GetCallable<H, H, H, H, H, H, H, H>();
+
+ Handle<Smi> arg1 = Handle<Smi>(Smi::FromInt(1), handles.main_isolate());
+ Handle<Smi> arg2 = Handle<Smi>(Smi::FromInt(2), handles.main_isolate());
+ Handle<Smi> arg3 = Handle<Smi>(Smi::FromInt(3), handles.main_isolate());
+ Handle<Smi> arg4 = Handle<Smi>(Smi::FromInt(4), handles.main_isolate());
+ Handle<Smi> arg5 = Handle<Smi>(Smi::FromInt(5), handles.main_isolate());
+ Handle<Smi> arg6 = Handle<Smi>(Smi::FromInt(6), handles.main_isolate());
+ Handle<Smi> arg7 = Handle<Smi>(Smi::FromInt(7), handles.main_isolate());
+ Handle<Smi> arg8 = Handle<Smi>(Smi::FromInt(8), handles.main_isolate());
+ // Check for Smis.
+ Handle<Object> return_val =
+ callable(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
+ .ToHandleChecked();
+ CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(36));
+}
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();
HandleScope scope(isolate);
// Allocate and initialize BytecodeArray
- Handle<BytecodeArray> array =
- factory->NewBytecodeArray(kRawBytesSize, kRawBytes, kFrameSize);
+ Handle<BytecodeArray> 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());
BytecodeArrayBuilder builder(isolate());
builder.set_locals_count(1);
+ builder.set_parameter_count(0);
CHECK_EQ(builder.locals_count(), 1);
// Emit constant loads.
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();
TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) {
BytecodeArrayBuilder builder(isolate());
+ builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.Return();
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