Fix logic error in assert in IsUndeclaredGlobal()
Recent changes in IC logic meant that CallStubs no longer use the Contextual bit. IsUndeclaredGlobal() needed to adjust for that. In fact, now the CL has morphed to remove the notion of storing contextual state in the IC at all, it just becomes some extra ic state of the load ic. This took some adjustment in harmony code to use the global receiver for certain stores. Now it's clearer that only LoadICs actually record any information about contextual or not. R=verwaest@chromium.org Review URL: https://codereview.chromium.org/140943002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18660 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e8f935a630
commit
155ef100e9
@ -647,7 +647,7 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm, ContextualMode mode) {
|
||||
// -----------------------------------
|
||||
|
||||
// Probe the stub cache.
|
||||
ExtraICState extra_ic_state = IC::ComputeExtraICState(mode);
|
||||
ExtraICState extra_ic_state = LoadIC::ComputeExtraICState(mode);
|
||||
Code::Flags flags = Code::ComputeFlags(
|
||||
Code::HANDLER, MONOMORPHIC, extra_ic_state,
|
||||
Code::NORMAL, Code::LOAD_IC);
|
||||
|
@ -2037,16 +2037,6 @@ LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
|
||||
LOperand* context = UseFixed(instr->context(), cp);
|
||||
LOperand* global_object = UseFixed(instr->global_object(), r1);
|
||||
LOperand* value = UseFixed(instr->value(), r0);
|
||||
LStoreGlobalGeneric* result =
|
||||
new(zone()) LStoreGlobalGeneric(context, global_object, value);
|
||||
return MarkAsCall(result, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
|
||||
LOperand* context = UseRegisterAtStart(instr->value());
|
||||
LInstruction* result =
|
||||
|
@ -160,7 +160,6 @@ class LCodeGen;
|
||||
V(StoreCodeEntry) \
|
||||
V(StoreContextSlot) \
|
||||
V(StoreGlobalCell) \
|
||||
V(StoreGlobalGeneric) \
|
||||
V(StoreKeyed) \
|
||||
V(StoreKeyedGeneric) \
|
||||
V(StoreNamedField) \
|
||||
@ -1666,28 +1665,6 @@ class LStoreGlobalCell V8_FINAL : public LTemplateInstruction<0, 1, 1> {
|
||||
};
|
||||
|
||||
|
||||
class LStoreGlobalGeneric V8_FINAL : public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreGlobalGeneric(LOperand* context,
|
||||
LOperand* global_object,
|
||||
LOperand* value) {
|
||||
inputs_[0] = context;
|
||||
inputs_[1] = global_object;
|
||||
inputs_[2] = value;
|
||||
}
|
||||
|
||||
LOperand* context() { return inputs_[0]; }
|
||||
LOperand* global_object() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric, "store-global-generic")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreGlobalGeneric)
|
||||
|
||||
Handle<Object> name() const { return hydrogen()->name(); }
|
||||
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
|
||||
};
|
||||
|
||||
|
||||
class LLoadContextSlot V8_FINAL : public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LLoadContextSlot(LOperand* context) {
|
||||
|
@ -3001,19 +3001,6 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
|
||||
ASSERT(ToRegister(instr->context()).is(cp));
|
||||
ASSERT(ToRegister(instr->global_object()).is(r1));
|
||||
ASSERT(ToRegister(instr->value()).is(r0));
|
||||
|
||||
__ mov(r2, Operand(instr->name()));
|
||||
Handle<Code> ic = StoreIC::initialize_stub(isolate(),
|
||||
instr->strict_mode_flag(),
|
||||
CONTEXTUAL);
|
||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
Register context = ToRegister(instr->context());
|
||||
Register result = ToRegister(instr->result());
|
||||
@ -4229,8 +4216,7 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
|
||||
// Name is always in r2.
|
||||
__ mov(r2, Operand(instr->name()));
|
||||
Handle<Code> ic = StoreIC::initialize_stub(isolate(),
|
||||
instr->strict_mode_flag(),
|
||||
NOT_CONTEXTUAL);
|
||||
instr->strict_mode_flag());
|
||||
CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
|
||||
}
|
||||
|
||||
|
@ -1058,7 +1058,7 @@ class KeyedLoadFieldStub: public LoadFieldStub {
|
||||
class KeyedArrayCallStub: public HICStub {
|
||||
public:
|
||||
KeyedArrayCallStub(bool holey, int argc) : HICStub(), argc_(argc) {
|
||||
bit_field_ = ContextualBits::encode(false) | HoleyBits::encode(holey);
|
||||
bit_field_ = HoleyBits::encode(holey);
|
||||
}
|
||||
|
||||
virtual Code::Kind kind() const { return Code::KEYED_CALL_IC; }
|
||||
@ -1087,9 +1087,10 @@ class KeyedArrayCallStub: public HICStub {
|
||||
return GetExtraICState() | ArgcBits::encode(argc_);
|
||||
}
|
||||
|
||||
class ContextualBits: public BitField<bool, 0, 1> {};
|
||||
STATIC_ASSERT(IC::Contextual::kShift == ContextualBits::kShift);
|
||||
STATIC_ASSERT(IC::Contextual::kSize == ContextualBits::kSize);
|
||||
// We have to start storing extra ic bits at 1, because calls use bit zero
|
||||
// for string stub state.
|
||||
STATIC_ASSERT(CallICBase::StringStubState::kShift == 0);
|
||||
STATIC_ASSERT(CallICBase::StringStubState::kSize == 1);
|
||||
class HoleyBits: public BitField<bool, 1, 1> {};
|
||||
STATIC_ASSERT(Code::kArgumentsBits <= kStubMinorKeyBits - 2);
|
||||
class ArgcBits: public BitField<int, 2, Code::kArgumentsBits> {};
|
||||
|
@ -237,7 +237,8 @@ static int DecodeIt(Isolate* isolate,
|
||||
Code* code = Code::GetCodeFromTargetAddress(relocinfo.target_address());
|
||||
Code::Kind kind = code->kind();
|
||||
if (code->is_inline_cache_stub()) {
|
||||
if (code->IsContextual()) {
|
||||
if (kind == Code::LOAD_IC &&
|
||||
LoadIC::GetContextualMode(code->extra_ic_state()) == CONTEXTUAL) {
|
||||
out.AddFormatted(" contextual,");
|
||||
}
|
||||
InlineCacheState ic_state = code->ic_state();
|
||||
|
@ -452,7 +452,7 @@ void FullCodeGenerator::CallLoadIC(ContextualMode mode, TypeFeedbackId id) {
|
||||
|
||||
|
||||
void FullCodeGenerator::CallStoreIC(ContextualMode mode, TypeFeedbackId id) {
|
||||
Handle<Code> ic = StoreIC::initialize_stub(isolate(), strict_mode(), mode);
|
||||
Handle<Code> ic = StoreIC::initialize_stub(isolate(), strict_mode());
|
||||
CallIC(ic, mode, id);
|
||||
}
|
||||
|
||||
|
@ -3351,12 +3351,6 @@ void HStoreGlobalCell::PrintDataTo(StringStream* stream) {
|
||||
}
|
||||
|
||||
|
||||
void HStoreGlobalGeneric::PrintDataTo(StringStream* stream) {
|
||||
stream->Add("%o = ", *name());
|
||||
value()->PrintNameTo(stream);
|
||||
}
|
||||
|
||||
|
||||
void HLoadContextSlot::PrintDataTo(StringStream* stream) {
|
||||
value()->PrintNameTo(stream);
|
||||
stream->Add("[%d]", slot_index());
|
||||
|
@ -165,7 +165,6 @@ class LChunkBuilder;
|
||||
V(StoreCodeEntry) \
|
||||
V(StoreContextSlot) \
|
||||
V(StoreGlobalCell) \
|
||||
V(StoreGlobalGeneric) \
|
||||
V(StoreKeyed) \
|
||||
V(StoreKeyedGeneric) \
|
||||
V(StoreNamedField) \
|
||||
@ -5742,52 +5741,6 @@ class HStoreGlobalCell V8_FINAL : public HUnaryOperation {
|
||||
};
|
||||
|
||||
|
||||
class HStoreGlobalGeneric : public HTemplateInstruction<3> {
|
||||
public:
|
||||
inline static HStoreGlobalGeneric* New(Zone* zone,
|
||||
HValue* context,
|
||||
HValue* global_object,
|
||||
Handle<Object> name,
|
||||
HValue* value,
|
||||
StrictModeFlag strict_mode_flag) {
|
||||
return new(zone) HStoreGlobalGeneric(context, global_object,
|
||||
name, value, strict_mode_flag);
|
||||
}
|
||||
|
||||
HValue* context() { return OperandAt(0); }
|
||||
HValue* global_object() { return OperandAt(1); }
|
||||
Handle<Object> name() const { return name_; }
|
||||
HValue* value() { return OperandAt(2); }
|
||||
StrictModeFlag strict_mode_flag() { return strict_mode_flag_; }
|
||||
|
||||
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
|
||||
return Representation::Tagged();
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric)
|
||||
|
||||
private:
|
||||
HStoreGlobalGeneric(HValue* context,
|
||||
HValue* global_object,
|
||||
Handle<Object> name,
|
||||
HValue* value,
|
||||
StrictModeFlag strict_mode_flag)
|
||||
: name_(name),
|
||||
strict_mode_flag_(strict_mode_flag) {
|
||||
SetOperandAt(0, context);
|
||||
SetOperandAt(1, global_object);
|
||||
SetOperandAt(2, value);
|
||||
set_representation(Representation::Tagged());
|
||||
SetAllSideEffects();
|
||||
}
|
||||
|
||||
Handle<Object> name_;
|
||||
StrictModeFlag strict_mode_flag_;
|
||||
};
|
||||
|
||||
|
||||
class HLoadContextSlot V8_FINAL : public HUnaryOperation {
|
||||
public:
|
||||
enum Mode {
|
||||
|
@ -5868,8 +5868,8 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
|
||||
}
|
||||
} else {
|
||||
HGlobalObject* global_object = Add<HGlobalObject>();
|
||||
HStoreGlobalGeneric* instr =
|
||||
Add<HStoreGlobalGeneric>(global_object, var->name(),
|
||||
HStoreNamedGeneric* instr =
|
||||
Add<HStoreNamedGeneric>(global_object, var->name(),
|
||||
value, function_strict_mode_flag());
|
||||
USE(instr);
|
||||
ASSERT(instr->HasObservableSideEffects());
|
||||
|
@ -1319,7 +1319,7 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm, ContextualMode mode) {
|
||||
// -----------------------------------
|
||||
|
||||
// Probe the stub cache.
|
||||
ExtraICState extra_ic_state = IC::ComputeExtraICState(mode);
|
||||
ExtraICState extra_ic_state = LoadIC::ComputeExtraICState(mode);
|
||||
Code::Flags flags = Code::ComputeFlags(
|
||||
Code::HANDLER, MONOMORPHIC, extra_ic_state,
|
||||
Code::NORMAL, Code::LOAD_IC);
|
||||
|
@ -3196,19 +3196,6 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
|
||||
ASSERT(ToRegister(instr->context()).is(esi));
|
||||
ASSERT(ToRegister(instr->global_object()).is(edx));
|
||||
ASSERT(ToRegister(instr->value()).is(eax));
|
||||
|
||||
__ mov(ecx, instr->name());
|
||||
Handle<Code> ic = StoreIC::initialize_stub(isolate(),
|
||||
instr->strict_mode_flag(),
|
||||
CONTEXTUAL);
|
||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
Register context = ToRegister(instr->context());
|
||||
Register result = ToRegister(instr->result());
|
||||
@ -4499,8 +4486,7 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
|
||||
|
||||
__ mov(ecx, instr->name());
|
||||
Handle<Code> ic = StoreIC::initialize_stub(isolate(),
|
||||
instr->strict_mode_flag(),
|
||||
NOT_CONTEXTUAL);
|
||||
instr->strict_mode_flag());
|
||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
@ -2072,16 +2072,6 @@ LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
|
||||
LOperand* context = UseFixed(instr->context(), esi);
|
||||
LOperand* global_object = UseFixed(instr->global_object(), edx);
|
||||
LOperand* value = UseFixed(instr->value(), eax);
|
||||
LStoreGlobalGeneric* result =
|
||||
new(zone()) LStoreGlobalGeneric(context, global_object, value);
|
||||
return MarkAsCall(result, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
|
||||
LOperand* context = UseRegisterAtStart(instr->value());
|
||||
LInstruction* result =
|
||||
|
@ -160,7 +160,6 @@ class LCodeGen;
|
||||
V(StoreCodeEntry) \
|
||||
V(StoreContextSlot) \
|
||||
V(StoreGlobalCell) \
|
||||
V(StoreGlobalGeneric) \
|
||||
V(StoreKeyed) \
|
||||
V(StoreKeyedGeneric) \
|
||||
V(StoreNamedField) \
|
||||
@ -1669,28 +1668,6 @@ class LStoreGlobalCell V8_FINAL : public LTemplateInstruction<0, 1, 0> {
|
||||
};
|
||||
|
||||
|
||||
class LStoreGlobalGeneric V8_FINAL : public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreGlobalGeneric(LOperand* context,
|
||||
LOperand* global_object,
|
||||
LOperand* value) {
|
||||
inputs_[0] = context;
|
||||
inputs_[1] = global_object;
|
||||
inputs_[2] = value;
|
||||
}
|
||||
|
||||
LOperand* context() { return inputs_[0]; }
|
||||
LOperand* global_object() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric, "store-global-generic")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreGlobalGeneric)
|
||||
|
||||
Handle<Object> name() const { return hydrogen()->name(); }
|
||||
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
|
||||
};
|
||||
|
||||
|
||||
class LLoadContextSlot V8_FINAL : public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LLoadContextSlot(LOperand* context) {
|
||||
|
21
src/ic.cc
21
src/ic.cc
@ -626,7 +626,7 @@ MaybeObject* CallICBase::LoadFunction(Handle<Object> object,
|
||||
if (!lookup.IsFound()) {
|
||||
// If the object does not have the requested property, check which
|
||||
// exception we need to throw.
|
||||
return IsUndeclaredGlobal(object)
|
||||
return object->IsGlobalObject()
|
||||
? ReferenceError("not_defined", name)
|
||||
: TypeError("undefined_method", object, name);
|
||||
}
|
||||
@ -643,7 +643,7 @@ MaybeObject* CallICBase::LoadFunction(Handle<Object> object,
|
||||
if (lookup.IsInterceptor() && attr == ABSENT) {
|
||||
// If the object does not have the requested property, check which
|
||||
// exception we need to throw.
|
||||
return IsUndeclaredGlobal(object)
|
||||
return object->IsGlobalObject()
|
||||
? ReferenceError("not_defined", name)
|
||||
: TypeError("undefined_method", object, name);
|
||||
}
|
||||
@ -1102,7 +1102,7 @@ void IC::PatchCache(Handle<Type> type,
|
||||
|
||||
Handle<Code> LoadIC::initialize_stub(Isolate* isolate, ContextualMode mode) {
|
||||
Handle<Code> ic = isolate->stub_cache()->ComputeLoad(
|
||||
UNINITIALIZED, IC::ComputeExtraICState(mode));
|
||||
UNINITIALIZED, ComputeExtraICState(mode));
|
||||
return ic;
|
||||
}
|
||||
|
||||
@ -1110,7 +1110,7 @@ Handle<Code> LoadIC::initialize_stub(Isolate* isolate, ContextualMode mode) {
|
||||
Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate,
|
||||
ContextualMode mode) {
|
||||
return isolate->stub_cache()->ComputeLoad(
|
||||
PREMONOMORPHIC, IC::ComputeExtraICState(mode));
|
||||
PREMONOMORPHIC, ComputeExtraICState(mode));
|
||||
}
|
||||
|
||||
|
||||
@ -1570,7 +1570,7 @@ MaybeObject* StoreIC::Store(Handle<Object> object,
|
||||
if (!can_store &&
|
||||
strict_mode() == kStrictMode &&
|
||||
!(lookup.IsProperty() && lookup.IsReadOnly()) &&
|
||||
IsUndeclaredGlobal(object)) {
|
||||
object->IsGlobalObject()) {
|
||||
// Strict mode doesn't allow setting non-existent global property.
|
||||
return ReferenceError("not_defined", name);
|
||||
}
|
||||
@ -1598,9 +1598,8 @@ MaybeObject* StoreIC::Store(Handle<Object> object,
|
||||
|
||||
|
||||
Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
|
||||
StrictModeFlag strict_mode,
|
||||
ContextualMode mode) {
|
||||
ExtraICState extra_state = ComputeExtraICState(strict_mode, mode);
|
||||
StrictModeFlag strict_mode) {
|
||||
ExtraICState extra_state = ComputeExtraICState(strict_mode);
|
||||
Handle<Code> ic = isolate->stub_cache()->ComputeStore(
|
||||
UNINITIALIZED, extra_state);
|
||||
return ic;
|
||||
@ -1618,10 +1617,8 @@ Handle<Code> StoreIC::generic_stub() const {
|
||||
|
||||
|
||||
Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
|
||||
StrictModeFlag strict_mode,
|
||||
ContextualMode contextual_mode) {
|
||||
ExtraICState state = StoreIC::ComputeExtraICState(strict_mode,
|
||||
contextual_mode);
|
||||
StrictModeFlag strict_mode) {
|
||||
ExtraICState state = ComputeExtraICState(strict_mode);
|
||||
return isolate->stub_cache()->ComputeStore(PREMONOMORPHIC, state);
|
||||
}
|
||||
|
||||
|
91
src/ic.h
91
src/ic.h
@ -89,20 +89,6 @@ class IC {
|
||||
EXTRA_CALL_FRAME = 1
|
||||
};
|
||||
|
||||
// ExtraICState shared by all ICs.
|
||||
class Contextual: public BitField<ContextualMode, 0, 1> {};
|
||||
STATIC_ASSERT(static_cast<int>(NOT_CONTEXTUAL) == 0);
|
||||
static ExtraICState ComputeExtraICState(ContextualMode mode) {
|
||||
return Contextual::encode(mode);
|
||||
}
|
||||
|
||||
static ContextualMode GetContextualMode(ExtraICState state) {
|
||||
return Contextual::decode(state);
|
||||
}
|
||||
|
||||
static const ExtraICState kContextualState =
|
||||
static_cast<int>(CONTEXTUAL) << Contextual::kShift;
|
||||
|
||||
// Construct the IC structure with the given number of extra
|
||||
// JavaScript frames on the stack.
|
||||
IC(FrameDepth depth, Isolate* isolate);
|
||||
@ -120,30 +106,19 @@ class IC {
|
||||
// Clear the inline cache to initial state.
|
||||
static void Clear(Isolate* isolate, Address address);
|
||||
|
||||
// Returns if this IC is for contextual (no explicit receiver)
|
||||
// access to properties.
|
||||
bool IsUndeclaredGlobal(Handle<Object> receiver) {
|
||||
if (receiver->IsGlobalObject()) {
|
||||
return IsCallStub() || IsContextual();
|
||||
} else {
|
||||
ASSERT(!IsContextual());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool IsLoadStub() {
|
||||
bool IsLoadStub() const {
|
||||
return target()->is_load_stub() || target()->is_keyed_load_stub();
|
||||
}
|
||||
|
||||
bool IsStoreStub() {
|
||||
bool IsStoreStub() const {
|
||||
return target()->is_store_stub() || target()->is_keyed_store_stub();
|
||||
}
|
||||
|
||||
#endif
|
||||
bool IsCallStub() {
|
||||
bool IsCallStub() const {
|
||||
return target()->is_call_stub() || target()->is_keyed_call_stub();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Determines which map must be used for keeping the code stub.
|
||||
// These methods should not be called with undefined or null.
|
||||
@ -174,12 +149,6 @@ class IC {
|
||||
static Handle<Type> MapToType(Handle<Map> type);
|
||||
static Handle<Type> CurrentTypeOf(Handle<Object> object, Isolate* isolate);
|
||||
|
||||
ContextualMode contextual_mode() const {
|
||||
return Contextual::decode(extra_ic_state());
|
||||
}
|
||||
|
||||
bool IsContextual() const { return contextual_mode() == CONTEXTUAL; }
|
||||
|
||||
protected:
|
||||
// Get the call-site target; used for determining the state.
|
||||
Handle<Code> target() const { return target_; }
|
||||
@ -439,11 +408,38 @@ class KeyedCallIC: public CallICBase {
|
||||
|
||||
class LoadIC: public IC {
|
||||
public:
|
||||
// ExtraICState bits
|
||||
class Contextual: public BitField<ContextualMode, 0, 1> {};
|
||||
STATIC_ASSERT(static_cast<int>(NOT_CONTEXTUAL) == 0);
|
||||
|
||||
static ExtraICState ComputeExtraICState(ContextualMode mode) {
|
||||
return Contextual::encode(mode);
|
||||
}
|
||||
|
||||
static ContextualMode GetContextualMode(ExtraICState state) {
|
||||
return Contextual::decode(state);
|
||||
}
|
||||
|
||||
ContextualMode contextual_mode() const {
|
||||
return Contextual::decode(extra_ic_state());
|
||||
}
|
||||
|
||||
explicit LoadIC(FrameDepth depth, Isolate* isolate)
|
||||
: IC(depth, isolate) {
|
||||
ASSERT(IsLoadStub());
|
||||
}
|
||||
|
||||
// Returns if this IC is for contextual (no explicit receiver)
|
||||
// access to properties.
|
||||
bool IsUndeclaredGlobal(Handle<Object> receiver) {
|
||||
if (receiver->IsGlobalObject()) {
|
||||
return contextual_mode() == CONTEXTUAL;
|
||||
} else {
|
||||
ASSERT(contextual_mode() != CONTEXTUAL);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Code generator routines.
|
||||
static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); }
|
||||
static void GeneratePreMonomorphic(MacroAssembler* masm) {
|
||||
@ -462,6 +458,14 @@ class LoadIC: public IC {
|
||||
protected:
|
||||
virtual Code::Kind kind() const { return Code::LOAD_IC; }
|
||||
|
||||
void set_target(Code* code) {
|
||||
// The contextual mode must be preserved across IC patching.
|
||||
ASSERT(GetContextualMode(code->extra_ic_state()) ==
|
||||
GetContextualMode(target()->extra_ic_state()));
|
||||
|
||||
IC::set_target(code);
|
||||
}
|
||||
|
||||
virtual Handle<Code> slow_stub() const {
|
||||
return isolate()->builtins()->LoadIC_Slow();
|
||||
}
|
||||
@ -572,17 +576,11 @@ class KeyedLoadIC: public LoadIC {
|
||||
|
||||
class StoreIC: public IC {
|
||||
public:
|
||||
// ExtraICState bits
|
||||
class StrictModeState: public BitField<StrictModeFlag, 1, 1> {};
|
||||
static ExtraICState ComputeExtraICState(StrictModeFlag flag) {
|
||||
return StrictModeState::encode(flag);
|
||||
}
|
||||
|
||||
static ExtraICState ComputeExtraICState(StrictModeFlag flag,
|
||||
ContextualMode mode) {
|
||||
return StrictModeState::encode(flag) | Contextual::encode(mode);
|
||||
}
|
||||
|
||||
static StrictModeFlag GetStrictMode(ExtraICState state) {
|
||||
return StrictModeState::decode(state);
|
||||
}
|
||||
@ -615,8 +613,7 @@ class StoreIC: public IC {
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
static Handle<Code> initialize_stub(Isolate* isolate,
|
||||
StrictModeFlag strict_mode,
|
||||
ContextualMode mode);
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
MUST_USE_RESULT MaybeObject* Store(
|
||||
Handle<Object> object,
|
||||
@ -637,12 +634,11 @@ class StoreIC: public IC {
|
||||
}
|
||||
|
||||
virtual Handle<Code> pre_monomorphic_stub() {
|
||||
return pre_monomorphic_stub(isolate(), strict_mode(), contextual_mode());
|
||||
return pre_monomorphic_stub(isolate(), strict_mode());
|
||||
}
|
||||
|
||||
static Handle<Code> pre_monomorphic_stub(Isolate* isolate,
|
||||
StrictModeFlag strict_mode,
|
||||
ContextualMode contextual_mode);
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
// Update the inline cache and the global stub cache based on the
|
||||
// lookup result.
|
||||
@ -661,9 +657,6 @@ class StoreIC: public IC {
|
||||
// Strict mode must be preserved across IC patching.
|
||||
ASSERT(GetStrictMode(code->extra_ic_state()) ==
|
||||
GetStrictMode(target()->extra_ic_state()));
|
||||
// As must the contextual mode
|
||||
ASSERT(GetContextualMode(code->extra_ic_state()) ==
|
||||
GetContextualMode(target()->extra_ic_state()));
|
||||
IC::set_target(code);
|
||||
}
|
||||
|
||||
|
@ -646,7 +646,7 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm, ContextualMode mode) {
|
||||
// -----------------------------------
|
||||
|
||||
// Probe the stub cache.
|
||||
ExtraICState extra_ic_state = IC::ComputeExtraICState(mode);
|
||||
ExtraICState extra_ic_state = LoadIC::ComputeExtraICState(mode);
|
||||
Code::Flags flags = Code::ComputeFlags(
|
||||
Code::HANDLER, MONOMORPHIC, extra_ic_state,
|
||||
Code::NORMAL, Code::LOAD_IC);
|
||||
|
@ -2851,18 +2851,6 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
|
||||
ASSERT(ToRegister(instr->context()).is(cp));
|
||||
ASSERT(ToRegister(instr->global_object()).is(a1));
|
||||
ASSERT(ToRegister(instr->value()).is(a0));
|
||||
|
||||
__ li(a2, Operand(instr->name()));
|
||||
Handle<Code> ic = StoreIC::initialize_stub(isolate(),
|
||||
instr->strict_mode_flag(),
|
||||
CONTEXTUAL);
|
||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
Register context = ToRegister(instr->context());
|
||||
@ -4145,8 +4133,7 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
|
||||
// Name is always in a2.
|
||||
__ li(a2, Operand(instr->name()));
|
||||
Handle<Code> ic = StoreIC::initialize_stub(isolate(),
|
||||
instr->strict_mode_flag(),
|
||||
NOT_CONTEXTUAL);
|
||||
instr->strict_mode_flag());
|
||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
@ -1962,16 +1962,6 @@ LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
|
||||
LOperand* context = UseFixed(instr->context(), cp);
|
||||
LOperand* global_object = UseFixed(instr->global_object(), a1);
|
||||
LOperand* value = UseFixed(instr->value(), a0);
|
||||
LStoreGlobalGeneric* result =
|
||||
new(zone()) LStoreGlobalGeneric(context, global_object, value);
|
||||
return MarkAsCall(result, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
|
||||
LOperand* context = UseRegisterAtStart(instr->value());
|
||||
LInstruction* result =
|
||||
|
@ -159,7 +159,6 @@ class LCodeGen;
|
||||
V(StoreCodeEntry) \
|
||||
V(StoreContextSlot) \
|
||||
V(StoreGlobalCell) \
|
||||
V(StoreGlobalGeneric) \
|
||||
V(StoreKeyed) \
|
||||
V(StoreKeyedGeneric) \
|
||||
V(StoreNamedField) \
|
||||
@ -1646,28 +1645,6 @@ class LStoreGlobalCell V8_FINAL : public LTemplateInstruction<0, 1, 1> {
|
||||
};
|
||||
|
||||
|
||||
class LStoreGlobalGeneric V8_FINAL : public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
LStoreGlobalGeneric(LOperand* context,
|
||||
LOperand* global_object,
|
||||
LOperand* value) {
|
||||
inputs_[0] = context;
|
||||
inputs_[1] = global_object;
|
||||
inputs_[2] = value;
|
||||
}
|
||||
|
||||
LOperand* context() { return inputs_[0]; }
|
||||
LOperand* global_object() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric, "store-global-generic")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreGlobalGeneric)
|
||||
|
||||
Handle<Object> name() const { return hydrogen()->name(); }
|
||||
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
|
||||
};
|
||||
|
||||
|
||||
class LLoadContextSlot V8_FINAL : public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LLoadContextSlot(LOperand* context) {
|
||||
|
@ -10877,17 +10877,6 @@ bool Code::CanDeoptAt(Address pc) {
|
||||
}
|
||||
|
||||
|
||||
bool Code::IsContextual() {
|
||||
ASSERT(is_inline_cache_stub());
|
||||
Kind kind = this->kind();
|
||||
if (kind == STORE_IC || kind == LOAD_IC || kind == CALL_IC) {
|
||||
ExtraICState extra_state = extra_ic_state();
|
||||
return IC::GetContextualMode(extra_state) == CONTEXTUAL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Identify kind of code.
|
||||
const char* Code::Kind2String(Kind kind) {
|
||||
switch (kind) {
|
||||
|
@ -5234,7 +5234,6 @@ class Code: public HeapObject {
|
||||
kind == BINARY_OP_IC;
|
||||
}
|
||||
|
||||
bool IsContextual(); // Only valid for IC stubs.
|
||||
inline StubType type(); // Only valid for monomorphic IC stubs.
|
||||
inline int arguments_count(); // Only valid for call IC stubs.
|
||||
|
||||
|
@ -296,7 +296,8 @@ function PromiseOne(values) {
|
||||
|
||||
function SetUpPromise() {
|
||||
%CheckIsBootstrapping()
|
||||
global.Promise = $Promise;
|
||||
var global_receiver = %GlobalReceiver(global);
|
||||
global_receiver.Promise = $Promise;
|
||||
InstallFunctions($Promise, DONT_ENUM, [
|
||||
"defer", PromiseDeferred,
|
||||
"resolve", PromiseResolved,
|
||||
|
@ -72,7 +72,8 @@ function ProxyCreateFunction(handler, callTrap, constructTrap) {
|
||||
function SetUpProxy() {
|
||||
%CheckIsBootstrapping()
|
||||
|
||||
global.Proxy = $Proxy;
|
||||
var global_receiver = %GlobalReceiver(global);
|
||||
global_receiver.Proxy = $Proxy;
|
||||
|
||||
// Set up non-enumerable properties of the Proxy object.
|
||||
InstallFunctions($Proxy, DONT_ENUM, [
|
||||
|
@ -884,12 +884,10 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
|
||||
|
||||
static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) {
|
||||
// If the load is non-contextual, just return the undefined result.
|
||||
// Note that both keyed and non-keyed loads may end up here, so we
|
||||
// can't use either LoadIC or KeyedLoadIC constructors.
|
||||
// Note that both keyed and non-keyed loads may end up here.
|
||||
HandleScope scope(isolate);
|
||||
IC ic(IC::NO_EXTRA_FRAME, isolate);
|
||||
ASSERT(ic.IsLoadStub());
|
||||
if (!ic.IsContextual()) {
|
||||
LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
|
||||
if (ic.contextual_mode() != CONTEXTUAL) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
@ -1048,9 +1046,6 @@ Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) {
|
||||
int argc = Code::ExtractArgumentsCountFromFlags(flags);
|
||||
Code::Kind kind = Code::ExtractKindFromFlags(flags);
|
||||
if (kind == Code::CALL_IC) {
|
||||
// Call normal is always with a explict receiver.
|
||||
ASSERT(!CallIC::Contextual::decode(
|
||||
Code::ExtractExtraICStateFromFlags(flags)));
|
||||
CallIC::GenerateNormal(masm(), argc);
|
||||
} else {
|
||||
KeyedCallIC::GenerateNormal(masm(), argc);
|
||||
@ -1106,7 +1101,7 @@ Handle<Code> StubCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
|
||||
|
||||
Handle<Code> StubCompiler::CompileLoadMegamorphic(Code::Flags flags) {
|
||||
ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
|
||||
ContextualMode mode = IC::GetContextualMode(extra_state);
|
||||
ContextualMode mode = LoadIC::GetContextualMode(extra_state);
|
||||
LoadIC::GenerateMegamorphic(masm(), mode);
|
||||
Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadMegamorphic");
|
||||
PROFILE(isolate(),
|
||||
|
@ -517,9 +517,6 @@ class StubCompiler BASE_EMBEDDED {
|
||||
Isolate* isolate() { return isolate_; }
|
||||
Heap* heap() { return isolate()->heap(); }
|
||||
Factory* factory() { return isolate()->factory(); }
|
||||
ContextualMode contextual_mode() {
|
||||
return IC::GetContextualMode(extra_state());
|
||||
}
|
||||
|
||||
static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code);
|
||||
|
||||
@ -687,6 +684,10 @@ class LoadStubCompiler: public BaseLoadStoreStubCompiler {
|
||||
static Register* registers();
|
||||
|
||||
protected:
|
||||
ContextualMode contextual_mode() {
|
||||
return LoadIC::GetContextualMode(extra_state());
|
||||
}
|
||||
|
||||
virtual Register HandlerFrontendHeader(Handle<Type> type,
|
||||
Register object_reg,
|
||||
Handle<JSObject> holder,
|
||||
|
@ -1345,7 +1345,7 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm, ContextualMode mode) {
|
||||
// -----------------------------------
|
||||
|
||||
// Probe the stub cache.
|
||||
ExtraICState extra_ic_state = IC::ComputeExtraICState(mode);
|
||||
ExtraICState extra_ic_state = LoadIC::ComputeExtraICState(mode);
|
||||
Code::Flags flags = Code::ComputeFlags(
|
||||
Code::HANDLER, MONOMORPHIC, extra_ic_state,
|
||||
Code::NORMAL, Code::LOAD_IC);
|
||||
|
@ -2743,19 +2743,6 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
|
||||
ASSERT(ToRegister(instr->context()).is(rsi));
|
||||
ASSERT(ToRegister(instr->global_object()).is(rdx));
|
||||
ASSERT(ToRegister(instr->value()).is(rax));
|
||||
|
||||
__ Move(rcx, instr->name());
|
||||
Handle<Code> ic = StoreIC::initialize_stub(isolate(),
|
||||
instr->strict_mode_flag(),
|
||||
CONTEXTUAL);
|
||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
Register context = ToRegister(instr->context());
|
||||
Register result = ToRegister(instr->result());
|
||||
@ -4079,8 +4066,7 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
|
||||
|
||||
__ Move(rcx, instr->hydrogen()->name());
|
||||
Handle<Code> ic = StoreIC::initialize_stub(isolate(),
|
||||
instr->strict_mode_flag(),
|
||||
NOT_CONTEXTUAL);
|
||||
instr->strict_mode_flag());
|
||||
CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
||||
}
|
||||
|
||||
|
@ -1948,16 +1948,6 @@ LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
|
||||
LOperand* context = UseFixed(instr->context(), rsi);
|
||||
LOperand* global_object = UseFixed(instr->global_object(), rdx);
|
||||
LOperand* value = UseFixed(instr->value(), rax);
|
||||
LStoreGlobalGeneric* result =
|
||||
new(zone()) LStoreGlobalGeneric(context, global_object, value);
|
||||
return MarkAsCall(result, instr);
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
|
||||
LOperand* context = UseRegisterAtStart(instr->value());
|
||||
LInstruction* result =
|
||||
|
@ -158,7 +158,6 @@ class LCodeGen;
|
||||
V(StoreCodeEntry) \
|
||||
V(StoreContextSlot) \
|
||||
V(StoreGlobalCell) \
|
||||
V(StoreGlobalGeneric) \
|
||||
V(StoreKeyed) \
|
||||
V(StoreKeyedGeneric) \
|
||||
V(StoreNamedField) \
|
||||
@ -1611,28 +1610,6 @@ class LStoreGlobalCell V8_FINAL : public LTemplateInstruction<0, 1, 1> {
|
||||
};
|
||||
|
||||
|
||||
class LStoreGlobalGeneric V8_FINAL : public LTemplateInstruction<0, 3, 0> {
|
||||
public:
|
||||
explicit LStoreGlobalGeneric(LOperand* context,
|
||||
LOperand* global_object,
|
||||
LOperand* value) {
|
||||
inputs_[0] = context;
|
||||
inputs_[1] = global_object;
|
||||
inputs_[2] = value;
|
||||
}
|
||||
|
||||
LOperand* context() { return inputs_[0]; }
|
||||
LOperand* global_object() { return inputs_[1]; }
|
||||
LOperand* value() { return inputs_[2]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric, "store-global-generic")
|
||||
DECLARE_HYDROGEN_ACCESSOR(StoreGlobalGeneric)
|
||||
|
||||
Handle<Object> name() const { return hydrogen()->name(); }
|
||||
StrictModeFlag strict_mode_flag() { return hydrogen()->strict_mode_flag(); }
|
||||
};
|
||||
|
||||
|
||||
class LLoadContextSlot V8_FINAL : public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
explicit LLoadContextSlot(LOperand* context) {
|
||||
|
41
test/mjsunit/regress/regress-is-contextual.js
Normal file
41
test/mjsunit/regress/regress-is-contextual.js
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2013 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// CallIC accumulates feedback that string index is out of bounds, then
|
||||
// misses
|
||||
function foo(index) {
|
||||
return text.charAt(index);
|
||||
}
|
||||
|
||||
var text = "hi there";
|
||||
foo(0);
|
||||
foo(0);
|
||||
foo(100); // Accumulate feedback that index is out of bounds.
|
||||
text = false;
|
||||
|
||||
// This line ASSERTS in debug without fix.
|
||||
assertThrows(function () { foo(); }, TypeError);
|
Loading…
Reference in New Issue
Block a user