Commit 66e59373 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Add function literal support.

Adds function literal support and add support for OTHER_CALLS which can be
made when calling a function literal.

Adds the CreateClosure bytecode.

BUG=v8:4280
LOG=N

Review URL: https://codereview.chromium.org/1396693003

Cr-Commit-Position: refs/heads/master@{#31231}
parent e5320d8a
...@@ -315,6 +315,12 @@ void BytecodeGraphBuilder::VisitKeyedStoreICStrict( ...@@ -315,6 +315,12 @@ void BytecodeGraphBuilder::VisitKeyedStoreICStrict(
} }
void BytecodeGraphBuilder::VisitCreateClosure(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitCall( void BytecodeGraphBuilder::VisitCall(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED(); UNIMPLEMENTED();
......
...@@ -322,6 +322,14 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( ...@@ -322,6 +322,14 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure(
PretenureFlag tenured) {
DCHECK(FitsInImm8Operand(tenured));
Output(Bytecode::kCreateClosure, static_cast<uint8_t>(tenured));
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() { BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
if (LastBytecodeInSameBlock()) { if (LastBytecodeInSameBlock()) {
// If the previous bytecode puts a boolean in the accumulator // If the previous bytecode puts a boolean in the accumulator
......
...@@ -72,6 +72,9 @@ class BytecodeArrayBuilder { ...@@ -72,6 +72,9 @@ class BytecodeArrayBuilder {
int feedback_slot, int feedback_slot,
LanguageMode language_mode); LanguageMode language_mode);
// Create a new closure for the SharedFunctionInfo in the accumulator.
BytecodeArrayBuilder& CreateClosure(PretenureFlag tenured);
// Call a JS function. The JSFunction or Callable to be called should be in // Call a JS function. The JSFunction or Callable to be called should be in
// |callable|, the receiver should be in |receiver| and all subsequent // |callable|, the receiver should be in |receiver| and all subsequent
// arguments should be in registers <receiver + 1> to // arguments should be in registers <receiver + 1> to
......
...@@ -394,7 +394,14 @@ void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { ...@@ -394,7 +394,14 @@ void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
UNIMPLEMENTED(); // Find or build a shared function info.
Handle<SharedFunctionInfo> shared_info =
Compiler::GetSharedFunctionInfo(expr, info()->script(), info());
CHECK(!shared_info.is_null()); // TODO(rmcilroy): Set stack overflow?
builder()
->LoadLiteral(shared_info)
.CreateClosure(expr->pretenure() ? TENURED : NOT_TENURED);
} }
...@@ -679,10 +686,15 @@ void BytecodeGenerator::VisitCall(Call* expr) { ...@@ -679,10 +686,15 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()->StoreAccumulatorInRegister(callee); builder()->StoreAccumulatorInRegister(callee);
break; break;
} }
case Call::OTHER_CALL: {
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
Visit(callee_expr);
builder()->StoreAccumulatorInRegister(callee);
break;
}
case Call::LOOKUP_SLOT_CALL: case Call::LOOKUP_SLOT_CALL:
case Call::SUPER_CALL: case Call::SUPER_CALL:
case Call::POSSIBLY_EVAL_CALL: case Call::POSSIBLY_EVAL_CALL:
case Call::OTHER_CALL:
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
......
...@@ -105,6 +105,9 @@ namespace interpreter { ...@@ -105,6 +105,9 @@ namespace interpreter {
/* Cast operators */ \ /* Cast operators */ \
V(ToBoolean, OperandType::kNone) \ V(ToBoolean, OperandType::kNone) \
\ \
/* Closure allocation */ \
V(CreateClosure, OperandType::kImm8) \
\
/* Control Flow */ \ /* Control Flow */ \
V(Jump, OperandType::kImm8) \ V(Jump, OperandType::kImm8) \
V(JumpConstant, OperandType::kIdx8) \ V(JumpConstant, OperandType::kIdx8) \
......
...@@ -687,6 +687,23 @@ void Interpreter::DoJumpIfFalseConstant( ...@@ -687,6 +687,23 @@ void Interpreter::DoJumpIfFalseConstant(
} }
// CreateClosure <tenured>
//
// Creates a new closure for SharedFunctionInfo in the accumulator with the
// PretenureFlag <tenured>.
void Interpreter::DoCreateClosure(compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy): Possibly call FastNewClosureStub when possible instead of
// calling into the runtime.
Node* shared = __ GetAccumulator();
Node* tenured_raw = __ BytecodeOperandImm8(0);
Node* tenured = __ SmiTag(tenured_raw);
Node* result =
__ CallRuntime(Runtime::kInterpreterNewClosure, shared, tenured);
__ SetAccumulator(result);
__ Dispatch();
}
// Return // Return
// //
// Return the value in the accumulator. // Return the value in the accumulator.
......
...@@ -137,5 +137,15 @@ RUNTIME_FUNCTION(Runtime_InterpreterTypeOf) { ...@@ -137,5 +137,15 @@ RUNTIME_FUNCTION(Runtime_InterpreterTypeOf) {
} }
RUNTIME_FUNCTION(Runtime_InterpreterNewClosure) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
CONVERT_SMI_ARG_CHECKED(pretenured_flag, 1);
Handle<Context> context(isolate->context(), isolate);
return *isolate->factory()->NewFunctionFromSharedFunctionInfo(
shared, context, static_cast<PretenureFlag>(pretenured_flag));
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -227,7 +227,8 @@ namespace internal { ...@@ -227,7 +227,8 @@ namespace internal {
F(InterpreterGreaterThanOrEqual, 2, 1) \ F(InterpreterGreaterThanOrEqual, 2, 1) \
F(InterpreterToBoolean, 1, 1) \ F(InterpreterToBoolean, 1, 1) \
F(InterpreterLogicalNot, 1, 1) \ F(InterpreterLogicalNot, 1, 1) \
F(InterpreterTypeOf, 1, 1) F(InterpreterTypeOf, 1, 1) \
F(InterpreterNewClosure, 2, 1)
#define FOR_EACH_INTRINSIC_FUNCTION(F) \ #define FOR_EACH_INTRINSIC_FUNCTION(F) \
......
...@@ -121,6 +121,11 @@ static void CheckConstant(Handle<Object> expected, Object* actual) { ...@@ -121,6 +121,11 @@ static void CheckConstant(Handle<Object> expected, Object* actual) {
} }
static void CheckConstant(InstanceType expected, Object* actual) {
CHECK_EQ(expected, HeapObject::cast(actual)->map()->instance_type());
}
template <typename T> template <typename T>
static void CheckBytecodeArrayEqual(struct ExpectedSnippet<T> expected, static void CheckBytecodeArrayEqual(struct ExpectedSnippet<T> expected,
Handle<BytecodeArray> actual, Handle<BytecodeArray> actual,
...@@ -1813,6 +1818,63 @@ TEST(UnaryOperators) { ...@@ -1813,6 +1818,63 @@ TEST(UnaryOperators) {
} }
TEST(FunctionLiterals) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
ExpectedSnippet<InstanceType> snippets[] = {
{"return function(){ }",
0,
1,
5,
{
B(LdaConstant), U8(0), //
B(CreateClosure), U8(0), //
B(Return) //
},
1,
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
{"return (function(){ })()",
2 * kPointerSize,
1,
14,
{
B(LdaUndefined), //
B(Star), R(1), //
B(LdaConstant), U8(0), //
B(CreateClosure), U8(0), //
B(Star), R(0), //
B(Call), R(0), R(1), U8(0), //
B(Return) //
},
1,
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
{"return (function(x){ return x; })(1)",
3 * kPointerSize,
1,
18,
{
B(LdaUndefined), //
B(Star), R(1), //
B(LdaConstant), U8(0), //
B(CreateClosure), U8(0), //
B(Star), R(0), //
B(LdaSmi8), U8(1), //
B(Star), R(2), //
B(Call), R(0), R(1), U8(1), //
B(Return) //
},
1,
{InstanceType::SHARED_FUNCTION_INFO_TYPE}},
};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -1620,3 +1620,20 @@ TEST(InterpreterCallRuntime) { ...@@ -1620,3 +1620,20 @@ TEST(InterpreterCallRuntime) {
Handle<Object> return_val = callable().ToHandleChecked(); Handle<Object> return_val = callable().ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(55)); CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(55));
} }
TEST(InterpreterFunctionLiteral) {
HandleAndZoneScope handles;
// Test calling a function literal.
std::string source(
"function " + InterpreterTester::function_name() + "(a) {\n"
" return (function(x){ return x + 2; })(a);\n"
"}");
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<Handle<Object>>();
Handle<i::Object> return_val = callable(
Handle<Smi>(Smi::FromInt(3), handles.main_isolate())).ToHandleChecked();
CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
}
...@@ -57,6 +57,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -57,6 +57,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.StoreNamedProperty(reg, reg, 0, LanguageMode::STRICT) .StoreNamedProperty(reg, reg, 0, LanguageMode::STRICT)
.StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT); .StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT);
// Emit closure operations.
builder.CreateClosure(NOT_TENURED);
// Call operations. // Call operations.
builder.Call(reg, reg, 0); builder.Call(reg, reg, 0);
builder.CallRuntime(Runtime::kIsArray, reg, 1); builder.CallRuntime(Runtime::kIsArray, reg, 1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment