Commit 044a62be authored by leszeks's avatar leszeks Committed by Commit bot

[interpreter] Add fast path for dynamic global lookups

Adds a fast path for loading DYNAMIC_GLOBAL variables, which are lookup
variables that can be globally loaded, without calling the runtime, as long as
there was no context extension by a sloppy eval along their context chain.

BUG=v8:5263

Review-Url: https://codereview.chromium.org/2347143002
Cr-Commit-Position: refs/heads/master@{#39537}
parent cab644f3
...@@ -915,6 +915,33 @@ void BytecodeGraphBuilder::VisitLdaLookupContextSlotInsideTypeof() { ...@@ -915,6 +915,33 @@ void BytecodeGraphBuilder::VisitLdaLookupContextSlotInsideTypeof() {
BuildLdaLookupContextSlot(TypeofMode::INSIDE_TYPEOF); BuildLdaLookupContextSlot(TypeofMode::INSIDE_TYPEOF);
} }
void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) {
// TODO(leszeks): Build the fast path here.
// Slow path, do a runtime load lookup.
{
FrameStateBeforeAndAfter states(this);
Node* name =
jsgraph()->Constant(bytecode_iterator().GetConstantForIndexOperand(0));
const Operator* op =
javascript()->CallRuntime(typeof_mode == TypeofMode::NOT_INSIDE_TYPEOF
? Runtime::kLoadLookupSlot
: Runtime::kLoadLookupSlotInsideTypeof);
Node* value = NewNode(op, name);
environment()->BindAccumulator(value, &states);
}
}
void BytecodeGraphBuilder::VisitLdaLookupGlobalSlot() {
BuildLdaLookupGlobalSlot(TypeofMode::NOT_INSIDE_TYPEOF);
}
void BytecodeGraphBuilder::VisitLdaLookupGlobalSlotInsideTypeof() {
BuildLdaLookupGlobalSlot(TypeofMode::INSIDE_TYPEOF);
}
void BytecodeGraphBuilder::BuildStaLookupSlot(LanguageMode language_mode) { void BytecodeGraphBuilder::BuildStaLookupSlot(LanguageMode language_mode) {
FrameStateBeforeAndAfter states(this); FrameStateBeforeAndAfter states(this);
Node* value = environment()->LookupAccumulator(); Node* value = environment()->LookupAccumulator();
......
...@@ -132,6 +132,7 @@ class BytecodeGraphBuilder { ...@@ -132,6 +132,7 @@ class BytecodeGraphBuilder {
void BuildKeyedStore(LanguageMode language_mode); void BuildKeyedStore(LanguageMode language_mode);
void BuildLdaLookupSlot(TypeofMode typeof_mode); void BuildLdaLookupSlot(TypeofMode typeof_mode);
void BuildLdaLookupContextSlot(TypeofMode typeof_mode); void BuildLdaLookupContextSlot(TypeofMode typeof_mode);
void BuildLdaLookupGlobalSlot(TypeofMode typeof_mode);
void BuildStaLookupSlot(LanguageMode language_mode); void BuildStaLookupSlot(LanguageMode language_mode);
void BuildCall(TailCallMode tail_call_mode); void BuildCall(TailCallMode tail_call_mode);
void BuildThrow(); void BuildThrow();
......
...@@ -307,6 +307,18 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupContextSlot( ...@@ -307,6 +307,18 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupContextSlot(
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupGlobalSlot(
const Handle<String> name, TypeofMode typeof_mode, int feedback_slot,
int depth) {
Bytecode bytecode = (typeof_mode == INSIDE_TYPEOF)
? Bytecode::kLdaLookupGlobalSlotInsideTypeof
: Bytecode::kLdaLookupGlobalSlot;
size_t name_index = GetConstantPoolEntry(name);
Output(bytecode, UnsignedOperand(name_index), UnsignedOperand(feedback_slot),
UnsignedOperand(depth));
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot( BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot(
const Handle<String> name, LanguageMode language_mode) { const Handle<String> name, LanguageMode language_mode) {
Bytecode bytecode = BytecodeForStoreLookupSlot(language_mode); Bytecode bytecode = BytecodeForStoreLookupSlot(language_mode);
......
...@@ -138,6 +138,13 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -138,6 +138,13 @@ class BytecodeArrayBuilder final : public ZoneObject {
TypeofMode typeof_mode, TypeofMode typeof_mode,
int slot_index, int depth); int slot_index, int depth);
// Lookup the variable with |name|, which has its feedback in |feedback_slot|
// and is known to be global if not shadowed by a context extension somewhere
// up to |depth| in that context chain.
BytecodeArrayBuilder& LoadLookupGlobalSlot(const Handle<String> name,
TypeofMode typeof_mode,
int feedback_slot, int depth);
// Store value in the accumulator into the variable with |name|. // Store value in the accumulator into the variable with |name|.
BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name, BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name,
LanguageMode language_mode); LanguageMode language_mode);
......
...@@ -1977,6 +1977,12 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, ...@@ -1977,6 +1977,12 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
BuildHoleCheckForVariableLoad(variable); BuildHoleCheckForVariableLoad(variable);
break; break;
} }
case DYNAMIC_GLOBAL: {
int depth = scope()->ContextChainLengthUntilOutermostSloppyEval();
builder()->LoadLookupGlobalSlot(variable->name(), typeof_mode,
feedback_index(slot), depth);
break;
}
default: default:
builder()->LoadLookupSlot(variable->name(), typeof_mode); builder()->LoadLookupSlot(variable->name(), typeof_mode);
} }
......
...@@ -117,9 +117,13 @@ namespace interpreter { ...@@ -117,9 +117,13 @@ namespace interpreter {
V(LdaLookupSlot, AccumulatorUse::kWrite, OperandType::kIdx) \ V(LdaLookupSlot, AccumulatorUse::kWrite, OperandType::kIdx) \
V(LdaLookupContextSlot, AccumulatorUse::kWrite, OperandType::kIdx, \ V(LdaLookupContextSlot, AccumulatorUse::kWrite, OperandType::kIdx, \
OperandType::kIdx, OperandType::kUImm) \ OperandType::kIdx, OperandType::kUImm) \
V(LdaLookupGlobalSlot, AccumulatorUse::kWrite, OperandType::kIdx, \
OperandType::kIdx, OperandType::kUImm) \
V(LdaLookupSlotInsideTypeof, AccumulatorUse::kWrite, OperandType::kIdx) \ V(LdaLookupSlotInsideTypeof, AccumulatorUse::kWrite, OperandType::kIdx) \
V(LdaLookupContextSlotInsideTypeof, AccumulatorUse::kWrite, \ V(LdaLookupContextSlotInsideTypeof, AccumulatorUse::kWrite, \
OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) \ OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) \
V(LdaLookupGlobalSlotInsideTypeof, AccumulatorUse::kWrite, \
OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) \
V(StaLookupSlotSloppy, AccumulatorUse::kReadWrite, OperandType::kIdx) \ V(StaLookupSlotSloppy, AccumulatorUse::kReadWrite, OperandType::kIdx) \
V(StaLookupSlotStrict, AccumulatorUse::kReadWrite, OperandType::kIdx) \ V(StaLookupSlotStrict, AccumulatorUse::kReadWrite, OperandType::kIdx) \
\ \
......
...@@ -421,16 +421,14 @@ void Interpreter::DoMov(InterpreterAssembler* assembler) { ...@@ -421,16 +421,14 @@ void Interpreter::DoMov(InterpreterAssembler* assembler) {
__ Dispatch(); __ Dispatch();
} }
Node* Interpreter::BuildLoadGlobal(Callable ic, Node* Interpreter::BuildLoadGlobal(Callable ic, Node* context,
Node* feedback_slot,
InterpreterAssembler* assembler) { InterpreterAssembler* assembler) {
typedef LoadGlobalWithVectorDescriptor Descriptor; typedef LoadGlobalWithVectorDescriptor Descriptor;
// Get the global object.
Node* context = __ GetContext();
// Load the global via the LoadGlobalIC. // Load the global via the LoadGlobalIC.
Node* code_target = __ HeapConstant(ic.code()); Node* code_target = __ HeapConstant(ic.code());
Node* raw_slot = __ BytecodeOperandIdx(0); Node* smi_slot = __ SmiTag(feedback_slot);
Node* smi_slot = __ SmiTag(raw_slot);
Node* type_feedback_vector = __ LoadTypeFeedbackVector(); Node* type_feedback_vector = __ LoadTypeFeedbackVector();
return __ CallStub(ic.descriptor(), code_target, context, return __ CallStub(ic.descriptor(), code_target, context,
Arg(Descriptor::kSlot, smi_slot), Arg(Descriptor::kSlot, smi_slot),
...@@ -444,7 +442,11 @@ Node* Interpreter::BuildLoadGlobal(Callable ic, ...@@ -444,7 +442,11 @@ Node* Interpreter::BuildLoadGlobal(Callable ic,
void Interpreter::DoLdaGlobal(InterpreterAssembler* assembler) { void Interpreter::DoLdaGlobal(InterpreterAssembler* assembler) {
Callable ic = Callable ic =
CodeFactory::LoadGlobalICInOptimizedCode(isolate_, NOT_INSIDE_TYPEOF); CodeFactory::LoadGlobalICInOptimizedCode(isolate_, NOT_INSIDE_TYPEOF);
Node* result = BuildLoadGlobal(ic, assembler);
Node* context = __ GetContext();
Node* raw_slot = __ BytecodeOperandIdx(0);
Node* result = BuildLoadGlobal(ic, context, raw_slot, assembler);
__ SetAccumulator(result); __ SetAccumulator(result);
__ Dispatch(); __ Dispatch();
} }
...@@ -456,7 +458,11 @@ void Interpreter::DoLdaGlobal(InterpreterAssembler* assembler) { ...@@ -456,7 +458,11 @@ void Interpreter::DoLdaGlobal(InterpreterAssembler* assembler) {
void Interpreter::DoLdrGlobal(InterpreterAssembler* assembler) { void Interpreter::DoLdrGlobal(InterpreterAssembler* assembler) {
Callable ic = Callable ic =
CodeFactory::LoadGlobalICInOptimizedCode(isolate_, NOT_INSIDE_TYPEOF); CodeFactory::LoadGlobalICInOptimizedCode(isolate_, NOT_INSIDE_TYPEOF);
Node* result = BuildLoadGlobal(ic, assembler);
Node* context = __ GetContext();
Node* raw_slot = __ BytecodeOperandIdx(0);
Node* result = BuildLoadGlobal(ic, context, raw_slot, assembler);
Node* destination = __ BytecodeOperandReg(1); Node* destination = __ BytecodeOperandReg(1);
__ StoreRegister(result, destination); __ StoreRegister(result, destination);
__ Dispatch(); __ Dispatch();
...@@ -469,7 +475,11 @@ void Interpreter::DoLdrGlobal(InterpreterAssembler* assembler) { ...@@ -469,7 +475,11 @@ void Interpreter::DoLdrGlobal(InterpreterAssembler* assembler) {
void Interpreter::DoLdaGlobalInsideTypeof(InterpreterAssembler* assembler) { void Interpreter::DoLdaGlobalInsideTypeof(InterpreterAssembler* assembler) {
Callable ic = Callable ic =
CodeFactory::LoadGlobalICInOptimizedCode(isolate_, INSIDE_TYPEOF); CodeFactory::LoadGlobalICInOptimizedCode(isolate_, INSIDE_TYPEOF);
Node* result = BuildLoadGlobal(ic, assembler);
Node* context = __ GetContext();
Node* raw_slot = __ BytecodeOperandIdx(0);
Node* result = BuildLoadGlobal(ic, context, raw_slot, assembler);
__ SetAccumulator(result); __ SetAccumulator(result);
__ Dispatch(); __ Dispatch();
} }
...@@ -563,8 +573,8 @@ void Interpreter::DoStaContextSlot(InterpreterAssembler* assembler) { ...@@ -563,8 +573,8 @@ void Interpreter::DoStaContextSlot(InterpreterAssembler* assembler) {
void Interpreter::DoLdaLookupSlot(Runtime::FunctionId function_id, void Interpreter::DoLdaLookupSlot(Runtime::FunctionId function_id,
InterpreterAssembler* assembler) { InterpreterAssembler* assembler) {
Node* index = __ BytecodeOperandIdx(0); Node* name_index = __ BytecodeOperandIdx(0);
Node* name = __ LoadConstantPoolEntry(index); Node* name = __ LoadConstantPoolEntry(name_index);
Node* context = __ GetContext(); Node* context = __ GetContext();
Node* result = __ CallRuntime(function_id, context, name); Node* result = __ CallRuntime(function_id, context, name);
__ SetAccumulator(result); __ SetAccumulator(result);
...@@ -634,6 +644,56 @@ void Interpreter::DoLdaLookupContextSlotInsideTypeof( ...@@ -634,6 +644,56 @@ void Interpreter::DoLdaLookupContextSlotInsideTypeof(
DoLdaLookupContextSlot(Runtime::kLoadLookupSlotInsideTypeof, assembler); DoLdaLookupContextSlot(Runtime::kLoadLookupSlotInsideTypeof, assembler);
} }
void Interpreter::DoLdaLookupGlobalSlot(Runtime::FunctionId function_id,
InterpreterAssembler* assembler) {
Node* context = __ GetContext();
Node* name_index = __ BytecodeOperandIdx(0);
Node* feedback_slot = __ BytecodeOperandIdx(1);
Node* depth = __ BytecodeOperandUImm(2);
Label slowpath(assembler, Label::kDeferred);
// Check for context extensions to allow the fast path
__ GotoIfHasContextExtensionUpToDepth(context, depth, &slowpath);
// Fast path does a normal load global
{
Callable ic = CodeFactory::LoadGlobalICInOptimizedCode(
isolate_, function_id == Runtime::kLoadLookupSlotInsideTypeof
? INSIDE_TYPEOF
: NOT_INSIDE_TYPEOF);
Node* result = BuildLoadGlobal(ic, context, feedback_slot, assembler);
__ SetAccumulator(result);
__ Dispatch();
}
// Slow path when we have to call out to the runtime
__ Bind(&slowpath);
{
Node* name = __ LoadConstantPoolEntry(name_index);
Node* result = __ CallRuntime(function_id, context, name);
__ SetAccumulator(result);
__ Dispatch();
}
}
// LdaLookupGlobalSlot <name_index> <feedback_slot> <depth>
//
// Lookup the object with the name in constant pool entry |name_index|
// dynamically.
void Interpreter::DoLdaLookupGlobalSlot(InterpreterAssembler* assembler) {
DoLdaLookupGlobalSlot(Runtime::kLoadLookupSlot, assembler);
}
// LdaLookupGlobalSlotInsideTypeof <name_index> <feedback_slot> <depth>
//
// Lookup the object with the name in constant pool entry |name_index|
// dynamically without causing a NoReferenceError.
void Interpreter::DoLdaLookupGlobalSlotInsideTypeof(
InterpreterAssembler* assembler) {
DoLdaLookupGlobalSlot(Runtime::kLoadLookupSlotInsideTypeof, assembler);
}
void Interpreter::DoStaLookupSlot(LanguageMode language_mode, void Interpreter::DoStaLookupSlot(LanguageMode language_mode,
InterpreterAssembler* assembler) { InterpreterAssembler* assembler) {
Node* value = __ GetAccumulator(); Node* value = __ GetAccumulator();
......
...@@ -137,7 +137,13 @@ class Interpreter { ...@@ -137,7 +137,13 @@ class Interpreter {
void DoLdaLookupContextSlot(Runtime::FunctionId function_id, void DoLdaLookupContextSlot(Runtime::FunctionId function_id,
InterpreterAssembler* assembler); InterpreterAssembler* assembler);
// Generates code to perform a lookup slot store depending on |language_mode|. // Generates code to perform a lookup slot load via |function_id| that can
// fast path to a global load.
void DoLdaLookupGlobalSlot(Runtime::FunctionId function_id,
InterpreterAssembler* assembler);
// Generates code to perform a lookup slot store depending on
// |language_mode|.
void DoStaLookupSlot(LanguageMode language_mode, void DoStaLookupSlot(LanguageMode language_mode,
InterpreterAssembler* assembler); InterpreterAssembler* assembler);
...@@ -145,7 +151,9 @@ class Interpreter { ...@@ -145,7 +151,9 @@ class Interpreter {
compiler::Node* BuildLoadContextSlot(InterpreterAssembler* assembler); compiler::Node* BuildLoadContextSlot(InterpreterAssembler* assembler);
// Generates code to load a global. // Generates code to load a global.
compiler::Node* BuildLoadGlobal(Callable ic, InterpreterAssembler* assembler); compiler::Node* BuildLoadGlobal(Callable ic, compiler::Node* context,
compiler::Node* feedback_slot,
InterpreterAssembler* assembler);
// Generates code to load a named property. // Generates code to load a named property.
compiler::Node* BuildLoadNamedProperty(Callable ic, compiler::Node* BuildLoadNamedProperty(Callable ic,
......
...@@ -1117,6 +1117,56 @@ TEST(BytecodeGraphBuilderLookupContextSlot) { ...@@ -1117,6 +1117,56 @@ TEST(BytecodeGraphBuilderLookupContextSlot) {
} }
} }
TEST(BytecodeGraphBuilderLookupGlobalSlot) {
HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate();
Zone* zone = scope.main_zone();
Factory* factory = isolate->factory();
// Testing with eval called in the current context.
const char* inner_eval_prologue = "x = 0; function inner() {";
const char* inner_eval_epilogue = "}; return inner();";
ExpectedSnippet<0> inner_eval_snippets[] = {
{"eval(''); return x;", {factory->NewNumber(0)}},
{"eval('var x = 1'); return x;", {factory->NewNumber(1)}},
{"'use strict'; eval('var x = 1'); return x;", {factory->NewNumber(0)}}};
for (size_t i = 0; i < arraysize(inner_eval_snippets); i++) {
ScopedVector<char> script(1024);
SNPrintF(script, "function %s(p1) { %s %s %s } ; %s() ;", kFunctionName,
inner_eval_prologue, inner_eval_snippets[i].code_snippet,
inner_eval_epilogue, kFunctionName);
BytecodeGraphTester tester(isolate, zone, script.start());
auto callable = tester.GetCallable<>();
Handle<Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*inner_eval_snippets[i].return_value()));
}
// Testing with eval called in a parent context.
const char* outer_eval_prologue = "";
const char* outer_eval_epilogue =
"function inner() { return x; }; return inner();";
ExpectedSnippet<0> outer_eval_snippets[] = {
{"x = 0; eval('');", {factory->NewNumber(0)}},
{"x = 0; eval('var x = 1');", {factory->NewNumber(1)}},
{"'use strict'; x = 0; eval('var x = 1');", {factory->NewNumber(0)}}};
for (size_t i = 0; i < arraysize(outer_eval_snippets); i++) {
ScopedVector<char> script(1024);
SNPrintF(script, "function %s() { %s %s %s } ; %s() ;", kFunctionName,
outer_eval_prologue, outer_eval_snippets[i].code_snippet,
outer_eval_epilogue, kFunctionName);
BytecodeGraphTester tester(isolate, zone, script.start());
auto callable = tester.GetCallable<>();
Handle<Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*outer_eval_snippets[i].return_value()));
}
}
TEST(BytecodeGraphBuilderLookupSlotWide) { TEST(BytecodeGraphBuilderLookupSlotWide) {
HandleAndZoneScope scope; HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate(); Isolate* isolate = scope.main_isolate();
......
...@@ -13,7 +13,7 @@ snippet: " ...@@ -13,7 +13,7 @@ snippet: "
" "
frame size: 10 frame size: 10
parameter count: 1 parameter count: 1
bytecode array length: 71 bytecode array length: 73
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(3), B(CreateFunctionContext), U8(3),
B(PushContext), R(0), B(PushContext), R(0),
...@@ -41,7 +41,7 @@ bytecodes: [ ...@@ -41,7 +41,7 @@ bytecodes: [
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6), B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1), B(Star), R(1),
/* 14 E> */ B(Call), R(1), R(2), U8(2), U8(0), /* 14 E> */ B(Call), R(1), R(2), U8(2), U8(0),
/* 35 S> */ B(LdaLookupSlot), U8(2), /* 35 S> */ B(LdaLookupGlobalSlot), U8(2), U8(4), U8(1),
/* 45 S> */ B(Return), /* 45 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -58,7 +58,7 @@ snippet: " ...@@ -58,7 +58,7 @@ snippet: "
" "
frame size: 10 frame size: 10
parameter count: 1 parameter count: 1
bytecode array length: 72 bytecode array length: 74
bytecodes: [ bytecodes: [
B(CreateFunctionContext), U8(3), B(CreateFunctionContext), U8(3),
B(PushContext), R(0), B(PushContext), R(0),
...@@ -86,7 +86,7 @@ bytecodes: [ ...@@ -86,7 +86,7 @@ bytecodes: [
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6), B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1), B(Star), R(1),
/* 14 E> */ B(Call), R(1), R(2), U8(2), U8(0), /* 14 E> */ B(Call), R(1), R(2), U8(2), U8(0),
/* 35 S> */ B(LdaLookupSlotInsideTypeof), U8(2), /* 35 S> */ B(LdaLookupGlobalSlotInsideTypeof), U8(2), U8(4), U8(1),
B(TypeOf), B(TypeOf),
/* 52 S> */ B(Return), /* 52 S> */ B(Return),
] ]
...@@ -194,3 +194,53 @@ constant pool: [ ...@@ -194,3 +194,53 @@ constant pool: [
handlers: [ handlers: [
] ]
---
snippet: "
x = 20;
f = function(){
eval('var x = 10');
return x;
}
f();
"
frame size: 10
parameter count: 1
bytecode array length: 73
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
B(Ldar), R(this),
B(StaContextSlot), R(context), U8(4), U8(0),
B(CreateMappedArguments),
B(StaContextSlot), R(context), U8(6), U8(0),
B(Ldar), R(new_target),
B(StaContextSlot), R(context), U8(5), U8(0),
/* 34 E> */ B(StackCheck),
/* 40 S> */ B(LdaConstant), U8(0),
B(Star), R(3),
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1),
B(LdaConstant), U8(1),
B(Star), R(3),
B(LdaZero),
B(Star), R(7),
B(LdaSmi), U8(34),
B(Star), R(8),
B(LdaSmi), U8(40),
B(Star), R(9),
B(Mov), R(1), R(4),
B(Mov), R(3), R(5),
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1),
/* 40 E> */ B(Call), R(1), R(2), U8(2), U8(0),
/* 62 S> */ B(LdaLookupGlobalSlot), U8(2), U8(4), U8(1),
/* 72 S> */ B(Return),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["eval"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["var x = 10"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"],
]
handlers: [
]
...@@ -18,10 +18,10 @@ snippet: " ...@@ -18,10 +18,10 @@ snippet: "
" "
frame size: 0 frame size: 0
parameter count: 1 parameter count: 1
bytecode array length: 4 bytecode array length: 6
bytecodes: [ bytecodes: [
/* 10 E> */ B(StackCheck), /* 10 E> */ B(StackCheck),
/* 15 S> */ B(LdaLookupSlot), U8(0), /* 15 S> */ B(LdaLookupGlobalSlot), U8(0), U8(2), U8(1),
/* 25 S> */ B(Return), /* 25 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -91,10 +91,10 @@ snippet: " ...@@ -91,10 +91,10 @@ snippet: "
" "
frame size: 0 frame size: 0
parameter count: 1 parameter count: 1
bytecode array length: 5 bytecode array length: 7
bytecodes: [ bytecodes: [
/* 10 E> */ B(StackCheck), /* 10 E> */ B(StackCheck),
/* 15 S> */ B(LdaLookupSlotInsideTypeof), U8(0), /* 15 S> */ B(LdaLookupGlobalSlotInsideTypeof), U8(0), U8(2), U8(1),
B(TypeOf), B(TypeOf),
/* 32 S> */ B(Return), /* 32 S> */ B(Return),
] ]
......
...@@ -278,7 +278,7 @@ snippet: " ...@@ -278,7 +278,7 @@ snippet: "
" "
frame size: 1 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 1030 bytecode array length: 1034
bytecodes: [ bytecodes: [
/* 10 E> */ B(StackCheck), /* 10 E> */ B(StackCheck),
/* 22 S> */ B(LdaConstant), U8(0), /* 22 S> */ B(LdaConstant), U8(0),
...@@ -793,7 +793,7 @@ bytecodes: [ ...@@ -793,7 +793,7 @@ bytecodes: [
B(Star), R(0), B(Star), R(0),
/* 3082 S> */ B(LdaConstant), U8(255), /* 3082 S> */ B(LdaConstant), U8(255),
B(Star), R(0), B(Star), R(0),
/* 3086 S> */ B(Wide), B(LdaLookupSlot), U16(256), /* 3086 S> */ B(Wide), B(LdaLookupGlobalSlot), U16(256), U16(2), U16(1),
/* 3095 S> */ B(Return), /* 3095 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -1329,7 +1329,7 @@ snippet: " ...@@ -1329,7 +1329,7 @@ snippet: "
" "
frame size: 1 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 1031 bytecode array length: 1035
bytecodes: [ bytecodes: [
/* 10 E> */ B(StackCheck), /* 10 E> */ B(StackCheck),
/* 22 S> */ B(LdaConstant), U8(0), /* 22 S> */ B(LdaConstant), U8(0),
...@@ -1844,7 +1844,7 @@ bytecodes: [ ...@@ -1844,7 +1844,7 @@ bytecodes: [
B(Star), R(0), B(Star), R(0),
/* 3082 S> */ B(LdaConstant), U8(255), /* 3082 S> */ B(LdaConstant), U8(255),
B(Star), R(0), B(Star), R(0),
/* 3086 S> */ B(Wide), B(LdaLookupSlotInsideTypeof), U16(256), /* 3086 S> */ B(Wide), B(LdaLookupGlobalSlotInsideTypeof), U16(256), U16(2), U16(1),
B(TypeOf), B(TypeOf),
/* 3102 S> */ B(Return), /* 3102 S> */ B(Return),
] ]
......
...@@ -1814,6 +1814,13 @@ TEST(LookupSlot) { ...@@ -1814,6 +1814,13 @@ TEST(LookupSlot) {
" eval('var x = 10');\n" " eval('var x = 10');\n"
" return x;\n" " return x;\n"
"}\n" "}\n"
"f();\n",
"x = 20;\n"
"f = function(){\n"
" eval('var x = 10');\n"
" return x;\n"
"}\n"
"f();\n" "f();\n"
}; };
// clang-format on // clang-format on
......
...@@ -3906,6 +3906,47 @@ TEST(InterpreterLookupContextSlot) { ...@@ -3906,6 +3906,47 @@ TEST(InterpreterLookupContextSlot) {
} }
} }
TEST(InterpreterLookupGlobalSlot) {
HandleAndZoneScope handles;
Isolate* isolate = handles.main_isolate();
const char* inner_function_prologue = "function inner() {";
const char* inner_function_epilogue = "};";
const char* outer_function_epilogue = "return inner();";
std::tuple<const char*, const char*, Handle<Object>> lookup_slot[] = {
// Eval in inner context.
std::make_tuple("x = 0;", "eval(''); return x;",
handle(Smi::FromInt(0), isolate)),
std::make_tuple("x = 0;", "eval('var x = 1'); return x;",
handle(Smi::FromInt(1), isolate)),
std::make_tuple("x = 0;", "'use strict'; eval('var x = 1'); return x;",
handle(Smi::FromInt(0), isolate)),
// Eval in outer context.
std::make_tuple("x = 0; eval('');", "return x;",
handle(Smi::FromInt(0), isolate)),
std::make_tuple("x = 0; eval('var x = 1');", "return x;",
handle(Smi::FromInt(1), isolate)),
std::make_tuple("'use strict'; x = 0; eval('var x = 1');", "return x;",
handle(Smi::FromInt(0), isolate)),
};
for (size_t i = 0; i < arraysize(lookup_slot); i++) {
std::string body = std::string(std::get<0>(lookup_slot[i])) +
std::string(inner_function_prologue) +
std::string(std::get<1>(lookup_slot[i])) +
std::string(inner_function_epilogue) +
std::string(outer_function_epilogue);
std::string script = InterpreterTester::SourceForBody(body.c_str());
InterpreterTester tester(isolate, script.c_str());
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*std::get<2>(lookup_slot[i])));
}
}
TEST(InterpreterCallLookupSlot) { TEST(InterpreterCallLookupSlot) {
HandleAndZoneScope handles; HandleAndZoneScope handles;
Isolate* isolate = handles.main_isolate(); Isolate* isolate = handles.main_isolate();
......
...@@ -104,6 +104,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -104,6 +104,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.LoadLookupContextSlot(name, TypeofMode::NOT_INSIDE_TYPEOF, 1, 0) builder.LoadLookupContextSlot(name, TypeofMode::NOT_INSIDE_TYPEOF, 1, 0)
.LoadLookupContextSlot(name, TypeofMode::INSIDE_TYPEOF, 1, 0); .LoadLookupContextSlot(name, TypeofMode::INSIDE_TYPEOF, 1, 0);
// Emit load / store lookup slots with global fast paths.
builder.LoadLookupGlobalSlot(name, TypeofMode::NOT_INSIDE_TYPEOF, 1, 0)
.LoadLookupGlobalSlot(name, TypeofMode::INSIDE_TYPEOF, 1, 0);
// Emit closure operations. // Emit closure operations.
builder.CreateClosure(0, NOT_TENURED); builder.CreateClosure(0, NOT_TENURED);
......
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