2015-08-10 11:20:23 +00:00
|
|
|
// Copyright 2015 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "src/v8.h"
|
|
|
|
|
|
|
|
#include "src/execution.h"
|
|
|
|
#include "src/handles.h"
|
|
|
|
#include "src/interpreter/bytecode-array-builder.h"
|
|
|
|
#include "src/interpreter/interpreter.h"
|
|
|
|
#include "test/cctest/cctest.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
2015-08-18 15:29:21 +00:00
|
|
|
namespace interpreter {
|
2015-08-10 11:20:23 +00:00
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
|
|
|
|
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>
|
2015-08-10 11:20:23 +00:00
|
|
|
class InterpreterCallable {
|
|
|
|
public:
|
|
|
|
InterpreterCallable(Isolate* isolate, Handle<JSFunction> function)
|
|
|
|
: isolate_(isolate), function_(function) {}
|
|
|
|
virtual ~InterpreterCallable() {}
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
MaybeHandle<Object> operator()(A... args) {
|
|
|
|
return CallInterpreter(isolate_, function_, args...);
|
2015-08-10 11:20:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Isolate* isolate_;
|
|
|
|
Handle<JSFunction> function_;
|
|
|
|
};
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
|
2015-08-10 11:20:23 +00:00
|
|
|
class InterpreterTester {
|
|
|
|
public:
|
2015-09-02 13:03:06 +00:00
|
|
|
InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode,
|
|
|
|
MaybeHandle<TypeFeedbackVector> feedback_vector =
|
|
|
|
MaybeHandle<TypeFeedbackVector>())
|
|
|
|
: isolate_(isolate),
|
|
|
|
bytecode_(bytecode),
|
|
|
|
feedback_vector_(feedback_vector) {
|
2015-09-09 15:46:04 +00:00
|
|
|
i::FLAG_vector_stores = true;
|
2015-08-10 11:20:23 +00:00
|
|
|
i::FLAG_ignition = true;
|
2015-08-10 18:22:07 +00:00
|
|
|
// Ensure handler table is generated.
|
|
|
|
isolate->interpreter()->Initialize();
|
2015-08-10 11:20:23 +00:00
|
|
|
}
|
|
|
|
virtual ~InterpreterTester() {}
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
template <class... A>
|
|
|
|
InterpreterCallable<A...> GetCallable() {
|
|
|
|
return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>());
|
2015-08-10 11:20:23 +00:00
|
|
|
}
|
|
|
|
|
2015-09-02 13:03:06 +00:00
|
|
|
Handle<Object> NewObject(const char* script) {
|
|
|
|
return v8::Utils::OpenHandle(*CompileRun(script));
|
|
|
|
}
|
|
|
|
|
2015-08-10 11:20:23 +00:00
|
|
|
private:
|
|
|
|
Isolate* isolate_;
|
2015-08-27 10:32:26 +00:00
|
|
|
Handle<BytecodeArray> bytecode_;
|
2015-09-02 13:03:06 +00:00
|
|
|
MaybeHandle<TypeFeedbackVector> feedback_vector_;
|
2015-08-27 10:32:26 +00:00
|
|
|
|
|
|
|
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 += "){})";
|
2015-08-10 11:20:23 +00:00
|
|
|
|
|
|
|
Handle<JSFunction> function = v8::Utils::OpenHandle(
|
2015-08-27 10:32:26 +00:00
|
|
|
*v8::Handle<v8::Function>::Cast(CompileRun(function_text.c_str())));
|
|
|
|
function->ReplaceCode(*isolate_->builtins()->InterpreterEntryTrampoline());
|
|
|
|
function->shared()->set_function_data(*bytecode_);
|
2015-09-02 13:03:06 +00:00
|
|
|
if (!feedback_vector_.is_null()) {
|
|
|
|
function->shared()->set_feedback_vector(
|
|
|
|
*feedback_vector_.ToHandleChecked());
|
|
|
|
}
|
2015-08-10 11:20:23 +00:00
|
|
|
return function;
|
|
|
|
}
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(InterpreterTester);
|
|
|
|
};
|
|
|
|
|
2015-08-18 15:29:21 +00:00
|
|
|
} // namespace interpreter
|
2015-08-10 11:20:23 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|
|
|
|
|
2015-08-18 15:29:21 +00:00
|
|
|
using v8::internal::BytecodeArray;
|
|
|
|
using v8::internal::Handle;
|
|
|
|
using v8::internal::Object;
|
2015-09-09 15:46:04 +00:00
|
|
|
using v8::internal::Runtime;
|
2015-08-18 15:29:21 +00:00
|
|
|
using v8::internal::Smi;
|
2015-08-25 11:31:09 +00:00
|
|
|
using v8::internal::Token;
|
2015-08-10 11:20:23 +00:00
|
|
|
using namespace v8::internal::interpreter;
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterReturn) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-10 11:20:23 +00:00
|
|
|
Handle<Object> undefined_value =
|
|
|
|
handles.main_isolate()->factory()->undefined_value();
|
|
|
|
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-18 12:41:41 +00:00
|
|
|
builder.set_locals_count(0);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-10 11:20:23 +00:00
|
|
|
builder.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-10 11:20:23 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK(return_val.is_identical_to(undefined_value));
|
|
|
|
}
|
2015-08-18 15:29:21 +00:00
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterLoadUndefined) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> undefined_value =
|
|
|
|
handles.main_isolate()->factory()->undefined_value();
|
|
|
|
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.set_locals_count(0);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.LoadUndefined().Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK(return_val.is_identical_to(undefined_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterLoadNull) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> null_value = handles.main_isolate()->factory()->null_value();
|
|
|
|
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.set_locals_count(0);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.LoadNull().Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK(return_val.is_identical_to(null_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterLoadTheHole) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> the_hole_value =
|
|
|
|
handles.main_isolate()->factory()->the_hole_value();
|
|
|
|
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.set_locals_count(0);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.LoadTheHole().Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK(return_val.is_identical_to(the_hole_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterLoadTrue) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
|
|
|
|
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.set_locals_count(0);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.LoadTrue().Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK(return_val.is_identical_to(true_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterLoadFalse) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> false_value = handles.main_isolate()->factory()->false_value();
|
|
|
|
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.set_locals_count(0);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.LoadFalse().Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK(return_val.is_identical_to(false_value));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterLoadLiteral) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
|
|
|
i::Factory* factory = handles.main_isolate()->factory();
|
|
|
|
|
|
|
|
// Small Smis.
|
2015-08-18 15:29:21 +00:00
|
|
|
for (int i = -128; i < 128; i++) {
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.set_locals_count(0);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.LoadLiteral(Smi::FromInt(i)).Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(i));
|
|
|
|
}
|
2015-08-28 15:40:52 +00:00
|
|
|
|
|
|
|
// Large Smis.
|
|
|
|
{
|
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
|
|
|
builder.set_locals_count(0);
|
|
|
|
builder.set_parameter_count(1);
|
|
|
|
builder.LoadLiteral(Smi::FromInt(0x12345678)).Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
|
|
|
auto callable = tester.GetCallable<>();
|
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x12345678));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Heap numbers.
|
|
|
|
{
|
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
|
|
|
builder.set_locals_count(0);
|
|
|
|
builder.set_parameter_count(1);
|
|
|
|
builder.LoadLiteral(factory->NewHeapNumber(-2.1e19)).Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
|
|
|
auto callable = tester.GetCallable<>();
|
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK_EQ(i::HeapNumber::cast(*return_val)->value(), -2.1e19);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Strings.
|
|
|
|
{
|
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
|
|
|
builder.set_locals_count(0);
|
|
|
|
builder.set_parameter_count(1);
|
|
|
|
Handle<i::String> string = factory->NewStringFromAsciiChecked("String");
|
|
|
|
builder.LoadLiteral(string).Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
|
|
|
auto callable = tester.GetCallable<>();
|
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK(i::String::cast(*return_val)->Equals(*string));
|
|
|
|
}
|
2015-08-18 15:29:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterLoadStoreRegisters) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
|
|
|
|
for (int i = 0; i <= Register::kMaxRegisterIndex; i++) {
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-18 15:29:21 +00:00
|
|
|
builder.set_locals_count(i + 1);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-18 15:29:21 +00:00
|
|
|
Register reg(i);
|
|
|
|
builder.LoadTrue()
|
|
|
|
.StoreAccumulatorInRegister(reg)
|
|
|
|
.LoadFalse()
|
|
|
|
.LoadAccumulatorWithRegister(reg)
|
|
|
|
.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-18 15:29:21 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK(return_val.is_identical_to(true_value));
|
|
|
|
}
|
|
|
|
}
|
2015-08-25 11:31:09 +00:00
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterAdd) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-25 11:31:09 +00:00
|
|
|
// TODO(rmcilroy): Do add tests for heap numbers and strings once we support
|
|
|
|
// them.
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-25 11:31:09 +00:00
|
|
|
builder.set_locals_count(1);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-25 11:31:09 +00:00
|
|
|
Register reg(0);
|
|
|
|
builder.LoadLiteral(Smi::FromInt(1))
|
|
|
|
.StoreAccumulatorInRegister(reg)
|
|
|
|
.LoadLiteral(Smi::FromInt(2))
|
|
|
|
.BinaryOperation(Token::Value::ADD, reg)
|
|
|
|
.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-25 11:31:09 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterSub) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-25 11:31:09 +00:00
|
|
|
// TODO(rmcilroy): Do add tests for heap numbers once we support them.
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-25 11:31:09 +00:00
|
|
|
builder.set_locals_count(1);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-25 11:31:09 +00:00
|
|
|
Register reg(0);
|
|
|
|
builder.LoadLiteral(Smi::FromInt(5))
|
|
|
|
.StoreAccumulatorInRegister(reg)
|
|
|
|
.LoadLiteral(Smi::FromInt(31))
|
|
|
|
.BinaryOperation(Token::Value::SUB, reg)
|
|
|
|
.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-25 11:31:09 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(-26));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterMul) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-25 11:31:09 +00:00
|
|
|
// TODO(rmcilroy): Do add tests for heap numbers once we support them.
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-25 11:31:09 +00:00
|
|
|
builder.set_locals_count(1);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-25 11:31:09 +00:00
|
|
|
Register reg(0);
|
|
|
|
builder.LoadLiteral(Smi::FromInt(111))
|
|
|
|
.StoreAccumulatorInRegister(reg)
|
|
|
|
.LoadLiteral(Smi::FromInt(6))
|
|
|
|
.BinaryOperation(Token::Value::MUL, reg)
|
|
|
|
.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-25 11:31:09 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(666));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterDiv) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-25 11:31:09 +00:00
|
|
|
// TODO(rmcilroy): Do add tests for heap numbers once we support them.
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-25 11:31:09 +00:00
|
|
|
builder.set_locals_count(1);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-25 11:31:09 +00:00
|
|
|
Register reg(0);
|
|
|
|
builder.LoadLiteral(Smi::FromInt(-20))
|
|
|
|
.StoreAccumulatorInRegister(reg)
|
|
|
|
.LoadLiteral(Smi::FromInt(5))
|
|
|
|
.BinaryOperation(Token::Value::DIV, reg)
|
|
|
|
.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-25 11:31:09 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(-4));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
TEST(InterpreterMod) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
2015-08-25 11:31:09 +00:00
|
|
|
// TODO(rmcilroy): Do add tests for heap numbers once we support them.
|
2015-08-28 15:40:52 +00:00
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-08-25 11:31:09 +00:00
|
|
|
builder.set_locals_count(1);
|
2015-08-27 10:32:26 +00:00
|
|
|
builder.set_parameter_count(1);
|
2015-08-25 11:31:09 +00:00
|
|
|
Register reg(0);
|
|
|
|
builder.LoadLiteral(Smi::FromInt(121))
|
|
|
|
.StoreAccumulatorInRegister(reg)
|
|
|
|
.LoadLiteral(Smi::FromInt(100))
|
|
|
|
.BinaryOperation(Token::Value::MOD, reg)
|
|
|
|
.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
2015-08-27 10:32:26 +00:00
|
|
|
auto callable = tester.GetCallable<>();
|
2015-08-25 11:31:09 +00:00
|
|
|
Handle<Object> return_val = callable().ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(21));
|
|
|
|
}
|
2015-08-27 10:32:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
TEST(InterpreterParameter1) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-09-02 13:03:06 +00:00
|
|
|
builder.set_locals_count(0);
|
2015-08-27 10:32:26 +00:00
|
|
|
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) {
|
2015-08-28 15:40:52 +00:00
|
|
|
HandleAndZoneScope handles;
|
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
2015-09-02 13:03:06 +00:00
|
|
|
builder.set_locals_count(0);
|
2015-08-27 10:32:26 +00:00
|
|
|
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));
|
|
|
|
}
|
2015-09-02 13:03:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
TEST(InterpreterLoadNamedProperty) {
|
|
|
|
HandleAndZoneScope handles;
|
|
|
|
i::Isolate* isolate = handles.main_isolate();
|
|
|
|
i::Factory* factory = isolate->factory();
|
|
|
|
|
|
|
|
i::Code::Kind ic_kinds[] = { i::Code::LOAD_IC };
|
|
|
|
i::FeedbackVectorSpec feedback_spec(0, 1, ic_kinds);
|
|
|
|
Handle<i::TypeFeedbackVector> vector =
|
|
|
|
factory->NewTypeFeedbackVector(&feedback_spec);
|
|
|
|
|
|
|
|
Handle<i::String> name = factory->NewStringFromAsciiChecked("val");
|
|
|
|
name = factory->string_table()->LookupString(isolate, name);
|
|
|
|
|
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
|
|
|
builder.set_locals_count(0);
|
|
|
|
builder.set_parameter_count(1);
|
|
|
|
builder.LoadLiteral(name)
|
|
|
|
.LoadNamedProperty(builder.Parameter(0), vector->first_ic_slot_index(),
|
|
|
|
i::SLOPPY)
|
|
|
|
.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
|
|
|
|
auto callable = tester.GetCallable<Handle<Object>>();
|
|
|
|
|
|
|
|
Handle<Object> object = tester.NewObject("({ val : 123 })");
|
|
|
|
// Test IC miss.
|
|
|
|
Handle<Object> return_val = callable(object).ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
|
|
|
|
|
|
|
|
// Test transition to monomorphic IC.
|
|
|
|
return_val = callable(object).ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
|
|
|
|
|
|
|
|
// Test transition to polymorphic IC.
|
|
|
|
Handle<Object> object2 = tester.NewObject("({ val : 456, other : 123 })");
|
|
|
|
return_val = callable(object2).ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(456));
|
|
|
|
|
|
|
|
// Test transition to megamorphic IC.
|
|
|
|
Handle<Object> object3 = tester.NewObject("({ val : 789, val2 : 123 })");
|
|
|
|
callable(object3).ToHandleChecked();
|
|
|
|
Handle<Object> object4 = tester.NewObject("({ val : 789, val3 : 123 })");
|
|
|
|
callable(object4).ToHandleChecked();
|
|
|
|
Handle<Object> object5 = tester.NewObject("({ val : 789, val4 : 123 })");
|
|
|
|
return_val = callable(object5).ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST(InterpreterLoadKeyedProperty) {
|
|
|
|
HandleAndZoneScope handles;
|
|
|
|
i::Isolate* isolate = handles.main_isolate();
|
|
|
|
i::Factory* factory = isolate->factory();
|
|
|
|
|
|
|
|
i::Code::Kind ic_kinds[] = { i::Code::KEYED_LOAD_IC };
|
|
|
|
i::FeedbackVectorSpec feedback_spec(0, 1, ic_kinds);
|
|
|
|
Handle<i::TypeFeedbackVector> vector =
|
|
|
|
factory->NewTypeFeedbackVector(&feedback_spec);
|
|
|
|
|
|
|
|
Handle<i::String> key = factory->NewStringFromAsciiChecked("key");
|
|
|
|
key = factory->string_table()->LookupString(isolate, key);
|
|
|
|
|
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
|
|
|
builder.set_locals_count(1);
|
|
|
|
builder.set_parameter_count(1);
|
|
|
|
builder.LoadLiteral(key)
|
|
|
|
.LoadKeyedProperty(builder.Parameter(0), vector->first_ic_slot_index(),
|
|
|
|
i::SLOPPY)
|
|
|
|
.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
|
|
|
|
auto callable = tester.GetCallable<Handle<Object>>();
|
|
|
|
|
|
|
|
Handle<Object> object = tester.NewObject("({ key : 123 })");
|
|
|
|
// Test IC miss.
|
|
|
|
Handle<Object> return_val = callable(object).ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
|
|
|
|
|
|
|
|
// Test transition to monomorphic IC.
|
|
|
|
return_val = callable(object).ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
|
|
|
|
|
|
|
|
// Test transition to megamorphic IC.
|
|
|
|
Handle<Object> object3 = tester.NewObject("({ key : 789, val2 : 123 })");
|
|
|
|
return_val = callable(object3).ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
|
|
|
|
}
|
2015-09-09 15:46:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
TEST(InterpreterStoreNamedProperty) {
|
|
|
|
HandleAndZoneScope handles;
|
|
|
|
i::Isolate* isolate = handles.main_isolate();
|
|
|
|
i::Factory* factory = isolate->factory();
|
|
|
|
|
|
|
|
i::Code::Kind ic_kinds[] = {i::Code::STORE_IC};
|
|
|
|
i::FeedbackVectorSpec feedback_spec(0, 1, ic_kinds);
|
|
|
|
Handle<i::TypeFeedbackVector> vector =
|
|
|
|
factory->NewTypeFeedbackVector(&feedback_spec);
|
|
|
|
|
|
|
|
Handle<i::String> name = factory->NewStringFromAsciiChecked("val");
|
|
|
|
name = factory->string_table()->LookupString(isolate, name);
|
|
|
|
|
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
|
|
|
builder.set_locals_count(1);
|
|
|
|
builder.set_parameter_count(1);
|
|
|
|
builder.LoadLiteral(name)
|
|
|
|
.StoreAccumulatorInRegister(Register(0))
|
|
|
|
.LoadLiteral(Smi::FromInt(999))
|
|
|
|
.StoreNamedProperty(builder.Parameter(0), Register(0),
|
|
|
|
vector->first_ic_slot_index(), i::SLOPPY)
|
|
|
|
.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(isolate, bytecode_array, vector);
|
|
|
|
auto callable = tester.GetCallable<Handle<Object>>();
|
|
|
|
Handle<Object> object = tester.NewObject("({ val : 123 })");
|
|
|
|
// Test IC miss.
|
|
|
|
Handle<Object> result;
|
|
|
|
callable(object).ToHandleChecked();
|
|
|
|
CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
|
|
|
|
CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
|
|
|
|
|
|
|
|
// Test transition to monomorphic IC.
|
|
|
|
callable(object).ToHandleChecked();
|
|
|
|
CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
|
|
|
|
CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
|
|
|
|
|
|
|
|
// Test transition to polymorphic IC.
|
|
|
|
Handle<Object> object2 = tester.NewObject("({ val : 456, other : 123 })");
|
|
|
|
callable(object2).ToHandleChecked();
|
|
|
|
CHECK(Runtime::GetObjectProperty(isolate, object2, name).ToHandle(&result));
|
|
|
|
CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
|
|
|
|
|
|
|
|
// Test transition to megamorphic IC.
|
|
|
|
Handle<Object> object3 = tester.NewObject("({ val : 789, val2 : 123 })");
|
|
|
|
callable(object3).ToHandleChecked();
|
|
|
|
Handle<Object> object4 = tester.NewObject("({ val : 789, val3 : 123 })");
|
|
|
|
callable(object4).ToHandleChecked();
|
|
|
|
Handle<Object> object5 = tester.NewObject("({ val : 789, val4 : 123 })");
|
|
|
|
callable(object5).ToHandleChecked();
|
|
|
|
CHECK(Runtime::GetObjectProperty(isolate, object5, name).ToHandle(&result));
|
|
|
|
CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST(InterpreterStoreKeyedProperty) {
|
|
|
|
HandleAndZoneScope handles;
|
|
|
|
i::Isolate* isolate = handles.main_isolate();
|
|
|
|
i::Factory* factory = isolate->factory();
|
|
|
|
|
|
|
|
i::Code::Kind ic_kinds[] = {i::Code::KEYED_STORE_IC};
|
|
|
|
i::FeedbackVectorSpec feedback_spec(0, 1, ic_kinds);
|
|
|
|
Handle<i::TypeFeedbackVector> vector =
|
|
|
|
factory->NewTypeFeedbackVector(&feedback_spec);
|
|
|
|
|
|
|
|
Handle<i::String> name = factory->NewStringFromAsciiChecked("val");
|
|
|
|
name = factory->string_table()->LookupString(isolate, name);
|
|
|
|
|
|
|
|
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
|
|
|
builder.set_locals_count(1);
|
|
|
|
builder.set_parameter_count(1);
|
|
|
|
builder.LoadLiteral(name)
|
|
|
|
.StoreAccumulatorInRegister(Register(0))
|
|
|
|
.LoadLiteral(Smi::FromInt(999))
|
|
|
|
.StoreKeyedProperty(builder.Parameter(0), Register(0),
|
|
|
|
vector->first_ic_slot_index(), i::SLOPPY)
|
|
|
|
.Return();
|
|
|
|
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
|
|
|
|
|
|
|
InterpreterTester tester(isolate, bytecode_array, vector);
|
|
|
|
auto callable = tester.GetCallable<Handle<Object>>();
|
|
|
|
Handle<Object> object = tester.NewObject("({ val : 123 })");
|
|
|
|
// Test IC miss.
|
|
|
|
Handle<Object> result;
|
|
|
|
callable(object).ToHandleChecked();
|
|
|
|
CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
|
|
|
|
CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
|
|
|
|
|
|
|
|
// Test transition to monomorphic IC.
|
|
|
|
callable(object).ToHandleChecked();
|
|
|
|
CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
|
|
|
|
CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
|
|
|
|
|
|
|
|
// Test transition to megamorphic IC.
|
|
|
|
Handle<Object> object2 = tester.NewObject("({ val : 456, other : 123 })");
|
|
|
|
callable(object2).ToHandleChecked();
|
|
|
|
CHECK(Runtime::GetObjectProperty(isolate, object2, name).ToHandle(&result));
|
|
|
|
CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
|
|
|
|
}
|