Commit d54ffadf authored by Daniel Ehrenberg's avatar Daniel Ehrenberg Committed by Commit Bot

[scopes] Fix sloppy-mode block-scoped function hoisting edge case

In edge cases such as the following, sloppy-mode block-scoped function
hoisting is expected to occur:

  eval(`
    with({a: 1}) {
      function a() {}
    }
  `)

In this case, there should be the equivalent of a var declaration
outside of the eval, which gets set to the value of the local function
a when the body of the with is executed.

Previously, the way that var declarations are hoisted out of eval
meant that the assignment to that var was an ordinary DYNAMIC_GLOBAL
assignment. However, such a lookup mode meant that the object in the
with scope received the assignment!

This patch fixes that error by marking the assignments produced by
the sloppy mode block scoped function hoisting desugaring so as to
generate a different runtime call which skips with scopes.

Bug: chromium:720247, v8:5135
Change-Id: Ie36322ddc9ca848bf680163e8c016f50d4597748
Reviewed-on: https://chromium-review.googlesource.com/529230
Commit-Queue: Daniel Ehrenberg <littledan@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46116}
parent 2a0bfdb5
......@@ -2158,6 +2158,18 @@ class Assignment final : public Expression {
bit_field_ = StoreModeField::update(bit_field_, mode);
}
// The assignment was generated as part of block-scoped sloppy-mode
// function hoisting, see
// ES#sec-block-level-function-declarations-web-legacy-compatibility-semantics
LookupHoistingMode lookup_hoisting_mode() const {
return static_cast<LookupHoistingMode>(
LookupHoistingModeField::decode(bit_field_));
}
void set_lookup_hoisting_mode(LookupHoistingMode mode) {
bit_field_ =
LookupHoistingModeField::update(bit_field_, static_cast<bool>(mode));
}
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FeedbackSlot AssignmentSlot() const { return slot_; }
......@@ -2174,6 +2186,8 @@ class Assignment final : public Expression {
class StoreModeField
: public BitField<KeyedAccessStoreMode, KeyTypeField::kNext, 3> {};
class TokenField : public BitField<Token::Value, StoreModeField::kNext, 7> {};
class LookupHoistingModeField : public BitField<bool, TokenField::kNext, 1> {
};
FeedbackSlot slot_;
Expression* target_;
......
......@@ -581,9 +581,10 @@ void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
if (factory) {
DCHECK(!is_being_lazily_parsed_);
Expression* assignment = factory->NewAssignment(
Assignment* assignment = factory->NewAssignment(
Token::ASSIGN, NewUnresolved(factory, name),
delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition);
assignment->set_lookup_hoisting_mode(LookupHoistingMode::kLegacySloppy);
Statement* statement =
factory->NewExpressionStatement(assignment, kNoSourcePosition);
delegate->set_statement(statement);
......
......@@ -1004,26 +1004,30 @@ void BytecodeGraphBuilder::VisitLdaLookupGlobalSlotInsideTypeof() {
BuildLdaLookupGlobalSlot(TypeofMode::INSIDE_TYPEOF);
}
void BytecodeGraphBuilder::BuildStaLookupSlot(LanguageMode language_mode) {
void BytecodeGraphBuilder::VisitStaLookupSlot() {
PrepareEagerCheckpoint();
Node* value = environment()->LookupAccumulator();
Node* name =
jsgraph()->Constant(bytecode_iterator().GetConstantForIndexOperand(0));
int bytecode_flags = bytecode_iterator().GetFlagOperand(1);
LanguageMode language_mode = static_cast<LanguageMode>(
interpreter::StoreLookupSlotFlags::LanguageModeBit::decode(
bytecode_flags));
LookupHoistingMode lookup_hoisting_mode = static_cast<LookupHoistingMode>(
interpreter::StoreLookupSlotFlags::LookupHoistingModeBit::decode(
bytecode_flags));
DCHECK_IMPLIES(lookup_hoisting_mode == LookupHoistingMode::kLegacySloppy,
is_sloppy(language_mode));
const Operator* op = javascript()->CallRuntime(
is_strict(language_mode) ? Runtime::kStoreLookupSlot_Strict
is_strict(language_mode)
? Runtime::kStoreLookupSlot_Strict
: lookup_hoisting_mode == LookupHoistingMode::kLegacySloppy
? Runtime::kStoreLookupSlot_SloppyHoisting
: Runtime::kStoreLookupSlot_Sloppy);
Node* store = NewNode(op, name, value);
environment()->BindAccumulator(store, Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitStaLookupSlotSloppy() {
BuildStaLookupSlot(LanguageMode::SLOPPY);
}
void BytecodeGraphBuilder::VisitStaLookupSlotStrict() {
BuildStaLookupSlot(LanguageMode::STRICT);
}
void BytecodeGraphBuilder::VisitLdaNamedProperty() {
PrepareEagerCheckpoint();
Node* object =
......
......@@ -162,7 +162,6 @@ class BytecodeGraphBuilder {
void BuildLdaLookupSlot(TypeofMode typeof_mode);
void BuildLdaLookupContextSlot(TypeofMode typeof_mode);
void BuildLdaLookupGlobalSlot(TypeofMode typeof_mode);
void BuildStaLookupSlot(LanguageMode language_mode);
void BuildCallVarArgs(TailCallMode tail_call_mode,
ConvertReceiverMode receiver_mode);
void BuildCall(TailCallMode tail_call_mode, ConvertReceiverMode receiver_mode,
......
......@@ -20,8 +20,6 @@ enum ContextLookupFlags {
DONT_FOLLOW_CHAINS = 0,
FOLLOW_CHAINS = FOLLOW_CONTEXT_CHAIN | FOLLOW_PROTOTYPE_CHAIN,
LEXICAL_TEST =
FOLLOW_CONTEXT_CHAIN | STOP_AT_DECLARATION_SCOPE | SKIP_WITH_CONTEXT,
};
......
......@@ -317,9 +317,10 @@ inline std::ostream& operator<<(std::ostream& os, const LanguageMode& mode) {
switch (mode) {
case SLOPPY: return os << "sloppy";
case STRICT: return os << "strict";
default: UNREACHABLE();
case LANGUAGE_END:
UNREACHABLE();
}
return os;
UNREACHABLE();
}
inline bool is_sloppy(LanguageMode language_mode) {
......@@ -361,6 +362,21 @@ inline std::ostream& operator<<(std::ostream& os, DeoptimizeKind kind) {
UNREACHABLE();
}
// Indicates whether the lookup is related to sloppy-mode block-scoped
// function hoisting, and is a synthetic assignment for that.
enum class LookupHoistingMode { kNormal, kLegacySloppy };
inline std::ostream& operator<<(std::ostream& os,
const LookupHoistingMode& mode) {
switch (mode) {
case LookupHoistingMode::kNormal:
return os << "normal hoisting";
case LookupHoistingMode::kLegacySloppy:
return os << "legacy sloppy hoisting";
}
UNREACHABLE();
}
// Mask for the sign bit in a smi.
const intptr_t kSmiSignMask = kIntptrSignBit;
......
......@@ -780,14 +780,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupGlobalSlot(
}
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot(
const AstRawString* name, LanguageMode language_mode) {
const AstRawString* name, LanguageMode language_mode,
LookupHoistingMode lookup_hoisting_mode) {
size_t name_index = GetConstantPoolEntry(name);
if (language_mode == SLOPPY) {
OutputStaLookupSlotSloppy(name_index);
} else {
DCHECK_EQ(language_mode, STRICT);
OutputStaLookupSlotStrict(name_index);
}
uint8_t flags =
StoreLookupSlotFlags::Encode(language_mode, lookup_hoisting_mode);
OutputStaLookupSlot(name_index, flags);
return *this;
}
......
......@@ -183,8 +183,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
int feedback_slot, int depth);
// Store value in the accumulator into the variable with |name|.
BytecodeArrayBuilder& StoreLookupSlot(const AstRawString* name,
LanguageMode language_mode);
BytecodeArrayBuilder& StoreLookupSlot(
const AstRawString* name, LanguageMode language_mode,
LookupHoistingMode lookup_hoisting_mode);
// Create a new closure for a SharedFunctionInfo which will be inserted at
// constant pool index |shared_function_info_entry|.
......
......@@ -84,6 +84,15 @@ SuspendFlags SuspendGeneratorBytecodeFlags::Decode(uint8_t flags) {
return FlagsBits::decode(flags);
}
// static
uint8_t StoreLookupSlotFlags::Encode(LanguageMode language_mode,
LookupHoistingMode lookup_hoisting_mode) {
DCHECK_IMPLIES(lookup_hoisting_mode == LookupHoistingMode::kLegacySloppy,
language_mode == SLOPPY);
return LanguageModeBit::encode(language_mode) |
LookupHoistingModeBit::encode(static_cast<bool>(lookup_hoisting_mode));
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -89,6 +89,19 @@ class SuspendGeneratorBytecodeFlags {
DISALLOW_IMPLICIT_CONSTRUCTORS(SuspendGeneratorBytecodeFlags);
};
class StoreLookupSlotFlags {
public:
class LanguageModeBit : public BitField8<bool, 0, 1> {};
class LookupHoistingModeBit
: public BitField8<bool, LanguageModeBit::kNext, 1> {};
static uint8_t Encode(LanguageMode language_mode,
LookupHoistingMode lookup_hoisting_mode);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StoreLookupSlotFlags);
};
} // namespace interpreter
} // namespace internal
} // namespace v8
......
......@@ -2331,10 +2331,9 @@ void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable,
}
}
void BytecodeGenerator::BuildVariableAssignment(Variable* variable,
Token::Value op,
FeedbackSlot slot,
HoleCheckMode hole_check_mode) {
void BytecodeGenerator::BuildVariableAssignment(
Variable* variable, Token::Value op, FeedbackSlot slot,
HoleCheckMode hole_check_mode, LookupHoistingMode lookup_hoisting_mode) {
VariableMode mode = variable->mode();
RegisterAllocationScope assignment_register_scope(this);
BytecodeLabel end_label;
......@@ -2407,7 +2406,8 @@ void BytecodeGenerator::BuildVariableAssignment(Variable* variable,
break;
}
case VariableLocation::LOOKUP: {
builder()->StoreLookupSlot(variable->raw_name(), language_mode());
builder()->StoreLookupSlot(variable->raw_name(), language_mode(),
lookup_hoisting_mode);
break;
}
case VariableLocation::MODULE: {
......@@ -2545,7 +2545,8 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
// Is the value in the accumulator safe? Yes, but scary.
VariableProxy* proxy = expr->target()->AsVariableProxy();
BuildVariableAssignment(proxy->var(), expr->op(), slot,
proxy->hole_check_mode());
proxy->hole_check_mode(),
expr->lookup_hoisting_mode());
break;
}
case NAMED_PROPERTY:
......
......@@ -112,9 +112,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildVariableLoadForAccumulatorValue(
Variable* variable, FeedbackSlot slot, HoleCheckMode hole_check_mode,
TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
void BuildVariableAssignment(Variable* variable, Token::Value op,
FeedbackSlot slot,
HoleCheckMode hole_check_mode);
void BuildVariableAssignment(
Variable* variable, Token::Value op, FeedbackSlot slot,
HoleCheckMode hole_check_mode,
LookupHoistingMode lookup_hoisting_mode = LookupHoistingMode::kNormal);
void BuildLiteralCompareNil(Token::Value compare_op, NilValue nil);
void BuildReturn();
void BuildAsyncReturn();
......
......@@ -70,8 +70,8 @@ namespace interpreter {
OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) \
V(LdaLookupGlobalSlotInsideTypeof, AccumulatorUse::kWrite, \
OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) \
V(StaLookupSlotSloppy, AccumulatorUse::kReadWrite, OperandType::kIdx) \
V(StaLookupSlotStrict, AccumulatorUse::kReadWrite, OperandType::kIdx) \
V(StaLookupSlot, AccumulatorUse::kReadWrite, OperandType::kIdx, \
OperandType::kFlag8) \
\
/* Register-accumulator transfers */ \
V(Ldar, AccumulatorUse::kWrite, OperandType::kReg) \
......
......@@ -500,34 +500,62 @@ IGNITION_HANDLER(LdaLookupGlobalSlotInsideTypeof,
LookupGlobalSlot(Runtime::kLoadLookupSlotInsideTypeof);
}
// StaLookupSlotSloppy <name_index>
// StaLookupSlotSloppy <name_index> <flags>
//
// Store the object in accumulator to the object with the name in constant
// pool entry |name_index| in sloppy mode.
IGNITION_HANDLER(StaLookupSlotSloppy, InterpreterAssembler) {
// pool entry |name_index|.
IGNITION_HANDLER(StaLookupSlot, InterpreterAssembler) {
Node* value = GetAccumulator();
Node* index = BytecodeOperandIdx(0);
Node* bytecode_flags = BytecodeOperandFlag(1);
Node* name = LoadConstantPoolEntry(index);
Node* context = GetContext();
Node* result =
CallRuntime(Runtime::kStoreLookupSlot_Sloppy, context, name, value);
SetAccumulator(result);
Dispatch();
}
Variable var_result(this, MachineRepresentation::kTagged);
// StaLookupSlotStrict <name_index>
//
// Store the object in accumulator to the object with the name in constant
// pool entry |name_index| in strict mode.
IGNITION_HANDLER(StaLookupSlotStrict, InterpreterAssembler) {
Node* value = GetAccumulator();
Node* index = BytecodeOperandIdx(0);
Node* name = LoadConstantPoolEntry(index);
Node* context = GetContext();
Node* result =
CallRuntime(Runtime::kStoreLookupSlot_Strict, context, name, value);
SetAccumulator(result);
Label sloppy(this), strict(this), end(this);
DCHECK_EQ(0, SLOPPY);
DCHECK_EQ(1, STRICT);
DCHECK_EQ(0, static_cast<int>(LookupHoistingMode::kNormal));
DCHECK_EQ(1, static_cast<int>(LookupHoistingMode::kLegacySloppy));
Branch(IsSetWord32<StoreLookupSlotFlags::LanguageModeBit>(bytecode_flags),
&strict, &sloppy);
BIND(&strict);
{
CSA_ASSERT(this, IsClearWord32<StoreLookupSlotFlags::LookupHoistingModeBit>(
bytecode_flags));
var_result.Bind(
CallRuntime(Runtime::kStoreLookupSlot_Strict, context, name, value));
Goto(&end);
}
BIND(&sloppy);
{
Label hoisting(this), ordinary(this);
Branch(IsSetWord32<StoreLookupSlotFlags::LookupHoistingModeBit>(
bytecode_flags),
&hoisting, &ordinary);
BIND(&hoisting);
{
var_result.Bind(CallRuntime(Runtime::kStoreLookupSlot_SloppyHoisting,
context, name, value));
Goto(&end);
}
BIND(&ordinary);
{
var_result.Bind(
CallRuntime(Runtime::kStoreLookupSlot_Sloppy, context, name, value));
Goto(&end);
}
}
BIND(&end);
{
SetAccumulator(var_result.value());
Dispatch();
}
}
// LdaNamedProperty <object> <name_index> <slot>
......
......@@ -248,7 +248,9 @@ Object* DeclareEvalHelper(Isolate* isolate, Handle<String> name,
VariableMode mode;
// Check for a conflict with a lexically scoped variable
context_arg->Lookup(name, LEXICAL_TEST, &index, &attributes, &init_flag,
const ContextLookupFlags lookup_flags = static_cast<ContextLookupFlags>(
FOLLOW_CONTEXT_CHAIN | STOP_AT_DECLARATION_SCOPE | SKIP_WITH_CONTEXT);
context_arg->Lookup(name, lookup_flags, &index, &attributes, &init_flag,
&mode);
if (attributes != ABSENT && IsLexicalVariableMode(mode)) {
// ES#sec-evaldeclarationinstantiation 5.a.i.1:
......@@ -941,8 +943,9 @@ RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall) {
namespace {
MaybeHandle<Object> StoreLookupSlot(Handle<String> name, Handle<Object> value,
LanguageMode language_mode) {
MaybeHandle<Object> StoreLookupSlot(
Handle<String> name, Handle<Object> value, LanguageMode language_mode,
ContextLookupFlags context_lookup_flags = FOLLOW_CHAINS) {
Isolate* const isolate = name->GetIsolate();
Handle<Context> context(isolate->context(), isolate);
......@@ -950,8 +953,8 @@ MaybeHandle<Object> StoreLookupSlot(Handle<String> name, Handle<Object> value,
PropertyAttributes attributes;
InitializationFlag flag;
VariableMode mode;
Handle<Object> holder =
context->Lookup(name, FOLLOW_CHAINS, &index, &attributes, &flag, &mode);
Handle<Object> holder = context->Lookup(name, context_lookup_flags, &index,
&attributes, &flag, &mode);
if (holder.is_null()) {
// In case of JSProxy, an exception might have been thrown.
if (isolate->has_pending_exception()) return MaybeHandle<Object>();
......@@ -1018,6 +1021,19 @@ RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy) {
RETURN_RESULT_OR_FAILURE(isolate, StoreLookupSlot(name, value, SLOPPY));
}
// Store into a dynamic context for sloppy-mode block-scoped function hoisting
// which leaks out of an eval. In particular, with-scopes are be skipped to
// reach the appropriate var-like declaration.
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_SloppyHoisting) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
const ContextLookupFlags lookup_flags = static_cast<ContextLookupFlags>(
FOLLOW_CONTEXT_CHAIN | STOP_AT_DECLARATION_SCOPE | SKIP_WITH_CONTEXT);
RETURN_RESULT_OR_FAILURE(isolate,
StoreLookupSlot(name, value, SLOPPY, lookup_flags));
}
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict) {
HandleScope scope(isolate);
......
......@@ -528,6 +528,7 @@ namespace internal {
F(LoadLookupSlot, 1, 1) \
F(LoadLookupSlotInsideTypeof, 1, 1) \
F(StoreLookupSlot_Sloppy, 2, 1) \
F(StoreLookupSlot_SloppyHoisting, 2, 1) \
F(StoreLookupSlot_Strict, 2, 1)
#define FOR_EACH_INTRINSIC_STRINGS(F) \
......
......@@ -11,7 +11,7 @@ snippet: "
"
frame size: 9
parameter count: 1
bytecode array length: 73
bytecode array length: 74
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
......@@ -23,7 +23,7 @@ bytecodes: [
B(StaCurrentContextSlot), U8(5),
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(CreateClosure), U8(0), U8(3), U8(2),
/* 36 E> */ B(StaLookupSlotSloppy), U8(1),
/* 36 E> */ B(StaLookupSlot), U8(1), U8(0),
/* 52 S> */ B(LdaLookupGlobalSlot), U8(2), U8(6), U8(1),
B(Star), R(1),
B(LdaConstant), U8(3),
......
......@@ -101,7 +101,7 @@ snippet: "
"
frame size: 9
parameter count: 1
bytecode array length: 62
bytecode array length: 63
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
......@@ -113,7 +113,7 @@ bytecodes: [
B(StaCurrentContextSlot), U8(5),
/* 10 E> */ B(StackCheck),
/* 14 S> */ B(LdaSmi), I8(20),
/* 16 E> */ B(StaLookupSlotSloppy), U8(0),
/* 16 E> */ B(StaLookupSlot), U8(0), U8(0),
/* 22 S> */ B(LdaLookupGlobalSlot), U8(1), U8(5), U8(1),
B(Star), R(1),
B(LdaConstant), U8(2),
......
......@@ -40,11 +40,11 @@ snippet: "
"
frame size: 0
parameter count: 1
bytecode array length: 7
bytecode array length: 8
bytecodes: [
/* 10 E> */ B(StackCheck),
/* 15 S> */ B(LdaSmi), I8(10),
/* 17 E> */ B(StaLookupSlotSloppy), U8(0),
/* 17 E> */ B(StaLookupSlot), U8(0), U8(0),
B(LdaUndefined),
/* 23 S> */ B(Return),
]
......@@ -65,11 +65,11 @@ snippet: "
"
frame size: 0
parameter count: 1
bytecode array length: 7
bytecode array length: 8
bytecodes: [
/* 10 E> */ B(StackCheck),
/* 29 S> */ B(LdaSmi), I8(10),
/* 31 E> */ B(StaLookupSlotStrict), U8(0),
/* 31 E> */ B(StaLookupSlot), U8(0), U8(1),
B(LdaUndefined),
/* 37 S> */ B(Return),
]
......
......@@ -2380,7 +2380,7 @@ snippet: "
"
frame size: 1
parameter count: 1
bytecode array length: 1033
bytecode array length: 1034
bytecodes: [
/* 10 E> */ B(StackCheck),
/* 22 S> */ B(LdaConstant), U8(0),
......@@ -2896,7 +2896,7 @@ bytecodes: [
/* 3082 S> */ B(LdaConstant), U8(255),
B(Star), R(0),
/* 3086 S> */ B(LdaSmi), I8(10),
/* 3088 E> */ B(Wide), B(StaLookupSlotSloppy), U16(256),
/* 3088 E> */ B(Wide), B(StaLookupSlot), U16(256), U8(0),
B(LdaUndefined),
/* 3093 S> */ B(Return),
]
......@@ -3434,7 +3434,7 @@ snippet: "
"
frame size: 1
parameter count: 1
bytecode array length: 1033
bytecode array length: 1034
bytecodes: [
/* 10 E> */ B(StackCheck),
/* 35 S> */ B(LdaConstant), U8(0),
......@@ -3950,7 +3950,7 @@ bytecodes: [
/* 3095 S> */ B(LdaConstant), U8(255),
B(Star), R(0),
/* 3099 S> */ B(LdaSmi), I8(10),
/* 3101 E> */ B(Wide), B(StaLookupSlotStrict), U16(256),
/* 3101 E> */ B(Wide), B(StaLookupSlot), U16(256), U8(1),
B(LdaUndefined),
/* 3106 S> */ B(Return),
]
......
......@@ -612,7 +612,6 @@ eval(`
`);
}();
// This test is incorrect BUG(v8:5168). The commented assertions are correct.
(function evalHoistingThroughSimpleCatch() {
try {
throw 0;
......@@ -636,12 +635,10 @@ eval(`
return 4;
} }`);
// assertEquals(0, f);
assertEquals(4, f());
assertEquals(0, f);
}
// assertEquals(4, f());
assertEquals(undefined, f);
assertEquals(4, f());
})();
let dontHoistGlobal;
......
// Copyright 2017 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.
assertEquals('function', typeof (function() {
return eval('with ({a: 1}) { function a() {} }; a')
})());
......@@ -117,8 +117,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Emit load / store lookup slots.
builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF)
.LoadLookupSlot(name, TypeofMode::INSIDE_TYPEOF)
.StoreLookupSlot(name, LanguageMode::SLOPPY)
.StoreLookupSlot(name, LanguageMode::STRICT);
.StoreLookupSlot(name, LanguageMode::SLOPPY, LookupHoistingMode::kNormal)
.StoreLookupSlot(name, LanguageMode::SLOPPY,
LookupHoistingMode::kLegacySloppy)
.StoreLookupSlot(name, LanguageMode::STRICT, LookupHoistingMode::kNormal);
// Emit load / store lookup slots with context fast paths.
builder.LoadLookupContextSlot(name, TypeofMode::NOT_INSIDE_TYPEOF, 1, 0)
......@@ -339,8 +341,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Emit wide load / store lookup slots.
builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF)
.LoadLookupSlot(wide_name, TypeofMode::INSIDE_TYPEOF)
.StoreLookupSlot(wide_name, LanguageMode::SLOPPY)
.StoreLookupSlot(wide_name, LanguageMode::STRICT);
.StoreLookupSlot(wide_name, LanguageMode::SLOPPY,
LookupHoistingMode::kNormal)
.StoreLookupSlot(wide_name, LanguageMode::SLOPPY,
LookupHoistingMode::kLegacySloppy)
.StoreLookupSlot(wide_name, LanguageMode::STRICT,
LookupHoistingMode::kNormal);
// CreateClosureWide
builder.CreateClosure(1000, 321, 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