From 85dbfb9a389e7b21bd2a63862202ee97fc5d7982 Mon Sep 17 00:00:00 2001 From: conradw Date: Thu, 18 Jun 2015 04:55:38 -0700 Subject: [PATCH] [strong] Implement strong mode restrictions on property access Implements the strong mode proposal's restrictions on property access. To be fully explored in a followup: proxies, interceptors, access checks, load from super BUG=v8:3956 LOG=N Review URL: https://codereview.chromium.org/1168093002 Cr-Commit-Position: refs/heads/master@{#29109} --- src/arm/code-stubs-arm.cc | 4 +- src/arm/full-codegen-arm.cc | 20 +- src/arm/lithium-codegen-arm.cc | 15 +- src/arm64/code-stubs-arm64.cc | 4 +- src/arm64/full-codegen-arm64.cc | 21 +- src/arm64/lithium-codegen-arm64.cc | 16 +- src/builtins.cc | 16 +- src/builtins.h | 19 +- src/code-factory.cc | 25 +- src/code-factory.h | 9 +- src/code-stubs-hydrogen.cc | 21 +- src/code-stubs.cc | 1 - src/code-stubs.h | 36 ++- src/compiler/ast-graph-builder.cc | 16 +- src/compiler/js-generic-lowering.cc | 6 +- src/compiler/js-operator.cc | 24 +- src/compiler/js-operator.h | 20 +- src/compiler/js-typed-lowering.cc | 4 +- src/full-codegen.cc | 4 +- src/full-codegen.h | 2 +- src/hydrogen-instructions.h | 22 +- src/hydrogen.cc | 34 +-- src/hydrogen.h | 7 +- src/ia32/code-stubs-ia32.cc | 4 +- src/ia32/full-codegen-ia32.cc | 20 +- src/ia32/lithium-codegen-ia32.cc | 15 +- src/ic/arm/handler-compiler-arm.cc | 24 ++ src/ic/arm/ic-arm.cc | 44 ++-- src/ic/arm64/handler-compiler-arm64.cc | 24 ++ src/ic/arm64/ic-arm64.cc | 51 ++-- src/ic/handler-compiler.cc | 13 +- src/ic/handler-compiler.h | 6 +- src/ic/ia32/handler-compiler-ia32.cc | 33 +++ src/ic/ia32/ic-ia32.cc | 41 ++-- src/ic/ic-compiler.cc | 13 +- src/ic/ic-compiler.h | 5 +- src/ic/ic-inl.h | 3 + src/ic/ic-state.h | 26 +- src/ic/ic.cc | 102 +++++--- src/ic/ic.h | 31 ++- src/ic/mips/handler-compiler-mips.cc | 24 ++ src/ic/mips/ic-mips.cc | 42 ++-- src/ic/mips64/handler-compiler-mips64.cc | 24 ++ src/ic/mips64/ic-mips64.cc | 31 ++- src/ic/ppc/handler-compiler-ppc.cc | 24 ++ src/ic/ppc/ic-ppc.cc | 42 ++-- src/ic/x64/handler-compiler-x64.cc | 33 +++ src/ic/x64/ic-x64.cc | 41 ++-- src/ic/x87/handler-compiler-x87.cc | 33 +++ src/ic/x87/ic-x87.cc | 41 ++-- src/messages.h | 2 + src/mips/code-stubs-mips.cc | 4 +- src/mips/full-codegen-mips.cc | 20 +- src/mips/lithium-codegen-mips.cc | 15 +- src/mips64/code-stubs-mips64.cc | 4 +- src/mips64/full-codegen-mips64.cc | 20 +- src/mips64/lithium-codegen-mips64.cc | 15 +- src/objects-inl.h | 26 +- src/objects.cc | 42 +++- src/objects.h | 30 ++- src/ppc/code-stubs-ppc.cc | 4 +- src/ppc/full-codegen-ppc.cc | 20 +- src/ppc/lithium-codegen-ppc.cc | 15 +- src/runtime/runtime-classes.cc | 70 ++++-- src/runtime/runtime-debug.cc | 2 +- src/runtime/runtime-object.cc | 221 +++++++++-------- src/runtime/runtime.h | 18 +- src/x64/code-stubs-x64.cc | 4 +- src/x64/full-codegen-x64.cc | 20 +- src/x64/lithium-codegen-x64.cc | 15 +- src/x87/code-stubs-x87.cc | 4 +- src/x87/full-codegen-x87.cc | 20 +- src/x87/lithium-codegen-x87.cc | 14 +- test/cctest/test-api.cc | 2 +- test/mjsunit/strong/functions.js | 4 +- test/mjsunit/strong/load-builtins.js | 42 ++++ .../strong/load-element-mutate-backing-store.js | 239 +++++++++++++++++++ test/mjsunit/strong/load-element.js | 264 +++++++++++++++++++++ .../strong/load-property-mutate-backing-store.js | 174 ++++++++++++++ test/mjsunit/strong/load-property.js | 200 ++++++++++++++++ .../compiler/js-type-feedback-unittest.cc | 2 +- .../compiler/js-typed-lowering-unittest.cc | 119 +++++----- 82 files changed, 2163 insertions(+), 624 deletions(-) create mode 100644 test/mjsunit/strong/load-builtins.js create mode 100644 test/mjsunit/strong/load-element-mutate-backing-store.js create mode 100644 test/mjsunit/strong/load-element.js create mode 100644 test/mjsunit/strong/load-property-mutate-backing-store.js create mode 100644 test/mjsunit/strong/load-property.js diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 5adf670..b0ef706 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -4372,7 +4372,7 @@ void LoadICTrampolineStub::Generate(MacroAssembler* masm) { void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { EmitLoadTypeFeedbackVector(masm, LoadWithVectorDescriptor::VectorRegister()); - KeyedLoadICStub stub(isolate()); + KeyedLoadICStub stub(isolate(), state()); stub.GenerateForTrampoline(masm); } @@ -4582,7 +4582,7 @@ void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); __ b(ne, &try_poly_name); Handle megamorphic_stub = - KeyedLoadIC::ChooseMegamorphicStub(masm->isolate()); + KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET); __ bind(&try_poly_name); diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index f5b90b6..2464157 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -2242,7 +2242,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ ldr(load_name, MemOperand(sp, 2 * kPointerSize)); __ mov(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(expr->KeyedLoadFeedbackSlot()))); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code(); CallIC(ic, TypeFeedbackId::None()); __ mov(r1, r0); __ str(r1, MemOperand(sp, 2 * kPointerSize)); @@ -2423,7 +2423,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { __ mov(LoadDescriptor::NameRegister(), Operand(key->value())); __ mov(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(prop->PropertyFeedbackSlot()))); - CallLoadIC(NOT_CONTEXTUAL); + CallLoadIC(NOT_CONTEXTUAL, language_mode()); } @@ -2435,13 +2435,14 @@ void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { DCHECK(prop->IsSuperAccess()); __ Push(key->value()); - __ CallRuntime(Runtime::kLoadFromSuper, 3); + __ Push(Smi::FromInt(language_mode())); + __ CallRuntime(Runtime::kLoadFromSuper, 4); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code(); __ mov(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(prop->PropertyFeedbackSlot()))); CallIC(ic); @@ -2450,9 +2451,10 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { // Stack: receiver, home_object, key. + __ Push(Smi::FromInt(language_mode())); SetSourcePosition(prop->position()); - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); } @@ -2998,6 +3000,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { __ ldr(scratch, MemOperand(sp, kPointerSize * 2)); __ Push(scratch); __ Push(key->value()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -3005,7 +3008,8 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadFromSuper, 4); // Replace home_object with target function. __ str(r0, MemOperand(sp, kPointerSize)); @@ -3058,6 +3062,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { __ ldr(scratch, MemOperand(sp, kPointerSize * 2)); __ Push(scratch); VisitForStackValue(prop->key()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -3065,7 +3070,8 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); // Replace home_object with target function. __ str(r0, MemOperand(sp, kPointerSize)); diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 8f6cdd3..a5639f8 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -2952,7 +2952,7 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { __ mov(LoadDescriptor::NameRegister(), Operand(instr->name())); EmitVectorLoadICRegisters(instr); ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; - Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, + Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, SLOPPY, PREMONOMORPHIC).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3048,9 +3048,10 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { // Name is always in r2. __ mov(LoadDescriptor::NameRegister(), Operand(instr->name())); EmitVectorLoadICRegisters(instr); - Handle ic = CodeFactory::LoadICInOptimizedCode( - isolate(), NOT_CONTEXTUAL, - instr->hydrogen()->initialization_state()).code(); + Handle ic = + CodeFactory::LoadICInOptimizedCode( + isolate(), NOT_CONTEXTUAL, instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } @@ -3357,9 +3358,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { EmitVectorLoadICRegisters(instr); } - Handle ic = - CodeFactory::KeyedLoadICInOptimizedCode( - isolate(), instr->hydrogen()->initialization_state()).code(); + Handle ic = CodeFactory::KeyedLoadICInOptimizedCode( + isolate(), instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS); } diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc index bd70150..ba40f44 100644 --- a/src/arm64/code-stubs-arm64.cc +++ b/src/arm64/code-stubs-arm64.cc @@ -4508,7 +4508,7 @@ void LoadICTrampolineStub::Generate(MacroAssembler* masm) { void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { EmitLoadTypeFeedbackVector(masm, LoadWithVectorDescriptor::VectorRegister()); - KeyedLoadICStub stub(isolate()); + KeyedLoadICStub stub(isolate(), state()); stub.GenerateForTrampoline(masm); } @@ -4717,7 +4717,7 @@ void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { __ JumpIfNotRoot(feedback, Heap::kmegamorphic_symbolRootIndex, &try_poly_name); Handle megamorphic_stub = - KeyedLoadIC::ChooseMegamorphicStub(masm->isolate()); + KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET); __ Bind(&try_poly_name); diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 2cf7142..ff47e34 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -2091,7 +2091,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { __ Mov(LoadDescriptor::NameRegister(), Operand(key->value())); __ Mov(LoadDescriptor::SlotRegister(), SmiFromSlot(prop->PropertyFeedbackSlot())); - CallLoadIC(NOT_CONTEXTUAL); + CallLoadIC(NOT_CONTEXTUAL, language_mode()); } @@ -2103,14 +2103,15 @@ void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { DCHECK(prop->IsSuperAccess()); __ Push(key->value()); - __ CallRuntime(Runtime::kLoadFromSuper, 3); + __ Push(Smi::FromInt(language_mode())); + __ CallRuntime(Runtime::kLoadFromSuper, 4); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); // Call keyed load IC. It has arguments key and receiver in x0 and x1. - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code(); __ Mov(LoadDescriptor::SlotRegister(), SmiFromSlot(prop->PropertyFeedbackSlot())); CallIC(ic); @@ -2119,9 +2120,10 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { // Stack: receiver, home_object, key. + __ Push(Smi::FromInt(language_mode())); SetSourcePosition(prop->position()); - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); } @@ -2683,14 +2685,15 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { __ Peek(scratch, kPointerSize); __ Push(x0, scratch); __ Push(key->value()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object // - this (receiver) // - this (receiver) <-- LoadFromSuper will pop here and below. // - home_object - // - key - __ CallRuntime(Runtime::kLoadFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadFromSuper, 4); // Replace home_object with target function. __ Poke(x0, kPointerSize); @@ -2743,6 +2746,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { __ Peek(scratch, kPointerSize); __ Push(x0, scratch); VisitForStackValue(prop->key()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -2750,7 +2754,8 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); // Replace home_object with target function. __ Poke(x0, kPointerSize); @@ -5198,7 +5203,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ Peek(load_name, 2 * kPointerSize); __ Mov(LoadDescriptor::SlotRegister(), SmiFromSlot(expr->KeyedLoadFeedbackSlot())); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code(); CallIC(ic, TypeFeedbackId::None()); __ Mov(x1, x0); __ Poke(x1, 2 * kPointerSize); diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index ec6e3c7..8275d8c 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -3306,7 +3306,7 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { __ Mov(LoadDescriptor::NameRegister(), Operand(instr->name())); EmitVectorLoadICRegisters(instr); ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; - Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, + Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, SLOPPY, PREMONOMORPHIC).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3576,9 +3576,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { EmitVectorLoadICRegisters(instr); } - Handle ic = - CodeFactory::KeyedLoadICInOptimizedCode( - isolate(), instr->hydrogen()->initialization_state()).code(); + Handle ic = CodeFactory::KeyedLoadICInOptimizedCode( + isolate(), instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); DCHECK(ToRegister(instr->result()).Is(x0)); @@ -3632,10 +3632,10 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister())); __ Mov(LoadDescriptor::NameRegister(), Operand(instr->name())); EmitVectorLoadICRegisters(instr); - - Handle ic = CodeFactory::LoadICInOptimizedCode( - isolate(), NOT_CONTEXTUAL, - instr->hydrogen()->initialization_state()).code(); + Handle ic = + CodeFactory::LoadICInOptimizedCode( + isolate(), NOT_CONTEXTUAL, instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); DCHECK(ToRegister(instr->result()).is(x0)); diff --git a/src/builtins.cc b/src/builtins.cc index 506492f..fe58a09 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -1278,17 +1278,12 @@ static void Generate_LoadIC_Getter_ForDeopt(MacroAssembler* masm) { static void Generate_LoadIC_Slow(MacroAssembler* masm) { - LoadIC::GenerateRuntimeGetProperty(masm); -} - - -static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) { - KeyedLoadIC::GenerateInitialize(masm); + NamedLoadHandlerCompiler::GenerateSlow(masm); } static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) { - KeyedLoadIC::GenerateRuntimeGetProperty(masm); + ElementHandlerCompiler::GenerateLoadSlow(masm); } @@ -1298,7 +1293,12 @@ static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) { static void Generate_KeyedLoadIC_Megamorphic(MacroAssembler* masm) { - KeyedLoadIC::GenerateMegamorphic(masm); + KeyedLoadIC::GenerateMegamorphic(masm, SLOPPY); +} + + +static void Generate_KeyedLoadIC_Megamorphic_Strong(MacroAssembler* masm) { + KeyedLoadIC::GenerateMegamorphic(masm, STRONG); } diff --git a/src/builtins.h b/src/builtins.h index 7d0d6c2..e973c80 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -86,9 +86,11 @@ enum BuiltinExtraArguments { V(StoreIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(LoadIC_Getter_ForDeopt, LOAD_IC, MONOMORPHIC, kNoExtraICState) \ - V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED, kNoExtraICState) \ V(KeyedLoadIC_Megamorphic, KEYED_LOAD_IC, MEGAMORPHIC, kNoExtraICState) \ \ + V(KeyedLoadIC_Megamorphic_Strong, KEYED_LOAD_IC, MEGAMORPHIC, \ + LoadICState::kStrongModeState) \ + \ V(StoreIC_Setter_ForDeopt, STORE_IC, MONOMORPHIC, \ StoreICState::kStrictModeState) \ \ @@ -104,7 +106,6 @@ enum BuiltinExtraArguments { V(KeyedStoreIC_Megamorphic_Strict, KEYED_STORE_IC, MEGAMORPHIC, \ StoreICState::kStrictModeState) \ \ - /* Uses KeyedLoadIC_Initialize; must be after in list. */ \ V(FunctionCall, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(FunctionApply, BUILTIN, UNINITIALIZED, kNoExtraICState) \ V(ReflectApply, BUILTIN, UNINITIALIZED, kNoExtraICState) \ @@ -126,13 +127,13 @@ enum BuiltinExtraArguments { CODE_AGE_LIST_WITH_ARG(DECLARE_CODE_AGE_BUILTIN, V) // Define list of builtin handlers implemented in assembly. -#define BUILTIN_LIST_H(V) \ - V(LoadIC_Slow, LOAD_IC) \ - V(KeyedLoadIC_Slow, KEYED_LOAD_IC) \ - V(StoreIC_Slow, STORE_IC) \ - V(KeyedStoreIC_Slow, KEYED_STORE_IC) \ - V(LoadIC_Normal, LOAD_IC) \ - V(StoreIC_Normal, STORE_IC) +#define BUILTIN_LIST_H(V) \ + V(LoadIC_Slow, LOAD_IC) \ + V(KeyedLoadIC_Slow, KEYED_LOAD_IC) \ + V(StoreIC_Slow, STORE_IC) \ + V(KeyedStoreIC_Slow, KEYED_STORE_IC) \ + V(LoadIC_Normal, LOAD_IC) \ + V(StoreIC_Normal, STORE_IC) // Define list of builtins used by the debugger implemented in assembly. #define BUILTIN_LIST_DEBUG_A(V) \ diff --git a/src/code-factory.cc b/src/code-factory.cc index fc7ea4a..8997747 100644 --- a/src/code-factory.cc +++ b/src/code-factory.cc @@ -13,35 +13,44 @@ namespace internal { // static -Callable CodeFactory::LoadIC(Isolate* isolate, ContextualMode mode) { +Callable CodeFactory::LoadIC(Isolate* isolate, ContextualMode mode, + LanguageMode language_mode) { return Callable( - LoadIC::initialize_stub(isolate, LoadICState(mode).GetExtraICState()), + LoadIC::initialize_stub( + isolate, LoadICState(mode, language_mode).GetExtraICState()), LoadDescriptor(isolate)); } // static Callable CodeFactory::LoadICInOptimizedCode( - Isolate* isolate, ContextualMode mode, + Isolate* isolate, ContextualMode mode, LanguageMode language_mode, InlineCacheState initialization_state) { auto code = LoadIC::initialize_stub_in_optimized_code( - isolate, LoadICState(mode).GetExtraICState(), initialization_state); + isolate, LoadICState(mode, language_mode).GetExtraICState(), + initialization_state); return Callable(code, LoadWithVectorDescriptor(isolate)); } // static -Callable CodeFactory::KeyedLoadIC(Isolate* isolate) { - return Callable(KeyedLoadIC::initialize_stub(isolate), +Callable CodeFactory::KeyedLoadIC(Isolate* isolate, + LanguageMode language_mode) { + ExtraICState state = + is_strong(language_mode) ? LoadICState::kStrongModeState : 0; + return Callable(KeyedLoadIC::initialize_stub(isolate, state), LoadDescriptor(isolate)); } // static Callable CodeFactory::KeyedLoadICInOptimizedCode( - Isolate* isolate, InlineCacheState initialization_state) { + Isolate* isolate, LanguageMode language_mode, + InlineCacheState initialization_state) { + ExtraICState state = + is_strong(language_mode) ? LoadICState::kStrongModeState : 0; auto code = KeyedLoadIC::initialize_stub_in_optimized_code( - isolate, initialization_state); + isolate, initialization_state, state); if (initialization_state != MEGAMORPHIC) { return Callable(code, LoadWithVectorDescriptor(isolate)); } diff --git a/src/code-factory.h b/src/code-factory.h index e26fc09..c043f55 100644 --- a/src/code-factory.h +++ b/src/code-factory.h @@ -32,12 +32,15 @@ class Callable final BASE_EMBEDDED { class CodeFactory final { public: // Initial states for ICs. - static Callable LoadIC(Isolate* isolate, ContextualMode mode); + static Callable LoadIC(Isolate* isolate, ContextualMode mode, + LanguageMode language_mode); static Callable LoadICInOptimizedCode(Isolate* isolate, ContextualMode mode, + LanguageMode language_mode, InlineCacheState initialization_state); - static Callable KeyedLoadIC(Isolate* isolate); + static Callable KeyedLoadIC(Isolate* isolate, LanguageMode language_mode); static Callable KeyedLoadICInOptimizedCode( - Isolate* isolate, InlineCacheState initialization_state); + Isolate* isolate, LanguageMode language_mode, + InlineCacheState initialization_state); static Callable CallIC(Isolate* isolate, int argc, CallICState::CallType call_type); static Callable CallICInOptimizedCode(Isolate* isolate, int argc, diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index 4573da1..eeeef2c 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -62,8 +62,7 @@ class CodeStubGraphBuilderBase : public HGraphBuilder { HContext* context() { return context_; } Isolate* isolate() { return info_->isolate(); } - HLoadNamedField* BuildLoadNamedField(HValue* object, - FieldIndex index); + HLoadNamedField* BuildLoadNamedField(HValue* object, FieldIndex index); void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index, Representation representation, bool transition_to_field); @@ -1901,7 +1900,8 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { HValue* hash = BuildElementIndexHash(key); - return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); + return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash, + casted_stub()->language_mode()); } @@ -2015,7 +2015,6 @@ void CodeStubGraphBuilder::BuildExternalElementLoad( HValue* CodeStubGraphBuilder::BuildCodeStub() { HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); HValue* key = GetParameter(LoadDescriptor::kNameIndex); - // Split into a smi/integer case and unique string case. HIfContinuation index_name_split_continuation(graph()->CreateBasicBlock(), graph()->CreateBasicBlock()); @@ -2059,7 +2058,8 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { HValue* hash = BuildElementIndexHash(key); - Push(BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash)); + Push(BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash, + casted_stub()->language_mode())); } kind_if.Else(); @@ -2137,10 +2137,8 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { hash = AddUncasted(hash, Add(Name::kHashShift)); - HValue* value = BuildUncheckedDictionaryElementLoad(receiver, - properties, - key, - hash); + HValue* value = BuildUncheckedDictionaryElementLoad( + receiver, properties, key, hash, casted_stub()->language_mode()); Push(value); } if_dict_properties.Else(); @@ -2215,10 +2213,11 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { inline_or_runtime.Else(); { // KeyedLookupCache miss; call runtime. - Add(receiver, key); + Add(receiver, key, + Add(casted_stub()->language_mode())); Push(Add( isolate()->factory()->empty_string(), - Runtime::FunctionForId(Runtime::kKeyedGetProperty), 2)); + Runtime::FunctionForId(Runtime::kKeyedGetProperty), 3)); } inline_or_runtime.End(); } diff --git a/src/code-stubs.cc b/src/code-stubs.cc index c007199..2cf4954 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -123,7 +123,6 @@ Handle PlatformCodeStub::GenerateCode() { // Create the code object. CodeDesc desc; masm.GetCode(&desc); - // Copy the generated code into a heap object. Code::Flags flags = Code::ComputeFlags( GetCodeKind(), diff --git a/src/code-stubs.h b/src/code-stubs.h index 515f2e5..ac373f0 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -2114,24 +2114,37 @@ class StringCharAtGenerator { class LoadDictionaryElementStub : public HydrogenCodeStub { public: - explicit LoadDictionaryElementStub(Isolate* isolate) - : HydrogenCodeStub(isolate) {} + explicit LoadDictionaryElementStub(Isolate* isolate, const LoadICState& state) + : HydrogenCodeStub(isolate) { + minor_key_ = state.GetExtraICState(); + } CallInterfaceDescriptor GetCallInterfaceDescriptor() override { return LoadWithVectorDescriptor(isolate()); } + LanguageMode language_mode() const { + return LoadICState::GetLanguageMode(MinorKey()); + } + DEFINE_HYDROGEN_CODE_STUB(LoadDictionaryElement, HydrogenCodeStub); }; class KeyedLoadGenericStub : public HydrogenCodeStub { public: - explicit KeyedLoadGenericStub(Isolate* isolate) : HydrogenCodeStub(isolate) {} + explicit KeyedLoadGenericStub(Isolate* isolate, const LoadICState& state) + : HydrogenCodeStub(isolate) { + minor_key_ = state.GetExtraICState(); + } Code::Kind GetCodeKind() const override { return Code::KEYED_LOAD_IC; } InlineCacheState GetICState() const override { return GENERIC; } + LanguageMode language_mode() const { + return LoadICState::GetLanguageMode(MinorKey()); + } + DEFINE_CALL_INTERFACE_DESCRIPTOR(Load); DEFINE_HYDROGEN_CODE_STUB(KeyedLoadGeneric, HydrogenCodeStub); @@ -2153,7 +2166,7 @@ class LoadICTrampolineStub : public PlatformCodeStub { return static_cast(minor_key_); } - private: + protected: LoadICState state() const { return LoadICState(static_cast(minor_key_)); } @@ -2165,8 +2178,8 @@ class LoadICTrampolineStub : public PlatformCodeStub { class KeyedLoadICTrampolineStub : public LoadICTrampolineStub { public: - explicit KeyedLoadICTrampolineStub(Isolate* isolate) - : LoadICTrampolineStub(isolate, LoadICState(0)) {} + explicit KeyedLoadICTrampolineStub(Isolate* isolate, const LoadICState& state) + : LoadICTrampolineStub(isolate, state) {} Code::Kind GetCodeKind() const override { return Code::KEYED_LOAD_IC; } @@ -2272,12 +2285,18 @@ class LoadICStub : public PlatformCodeStub { class KeyedLoadICStub : public PlatformCodeStub { public: - explicit KeyedLoadICStub(Isolate* isolate) : PlatformCodeStub(isolate) {} + explicit KeyedLoadICStub(Isolate* isolate, const LoadICState& state) + : PlatformCodeStub(isolate) { + minor_key_ = state.GetExtraICState(); + } void GenerateForTrampoline(MacroAssembler* masm); Code::Kind GetCodeKind() const override { return Code::KEYED_LOAD_IC; } InlineCacheState GetICState() const final { return DEFAULT; } + ExtraICState GetExtraICState() const final { + return static_cast(minor_key_); + } DEFINE_CALL_INTERFACE_DESCRIPTOR(LoadWithVector); DEFINE_PLATFORM_CODE_STUB(KeyedLoadIC, PlatformCodeStub); @@ -2321,6 +2340,9 @@ class VectorKeyedStoreICStub : public PlatformCodeStub { Code::Kind GetCodeKind() const final { return Code::KEYED_STORE_IC; } InlineCacheState GetICState() const final { return DEFAULT; } + virtual ExtraICState GetExtraICState() const final { + return static_cast(minor_key_); + } DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorStoreIC); DEFINE_PLATFORM_CODE_STUB(VectorKeyedStoreIC, PlatformCodeStub); diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 159536c..f967a97 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -3459,7 +3459,7 @@ static inline Node* Record(JSTypeFeedbackTable* js_type_feedback, Node* node, Node* AstGraphBuilder::BuildKeyedLoad(Node* object, Node* key, const ResolvedFeedbackSlot& feedback) { - const Operator* op = javascript()->LoadProperty(feedback); + const Operator* op = javascript()->LoadProperty(feedback, language_mode()); return Record(js_type_feedback_, NewNode(op, object, key, GetFeedbackVector()), feedback.slot()); } @@ -3468,8 +3468,8 @@ Node* AstGraphBuilder::BuildKeyedLoad(Node* object, Node* key, Node* AstGraphBuilder::BuildNamedLoad(Node* object, Handle name, const ResolvedFeedbackSlot& feedback, ContextualMode mode) { - const Operator* op = - javascript()->LoadNamed(MakeUnique(name), feedback, mode); + const Operator* op = javascript()->LoadNamed(MakeUnique(name), feedback, + language_mode(), mode); return Record(js_type_feedback_, NewNode(op, object, GetFeedbackVector()), feedback.slot()); } @@ -3494,8 +3494,9 @@ Node* AstGraphBuilder::BuildNamedSuperLoad( Node* receiver, Node* home_object, Handle name, const ResolvedFeedbackSlot& feedback) { Node* name_node = jsgraph()->Constant(name); - const Operator* op = javascript()->CallRuntime(Runtime::kLoadFromSuper, 3); - Node* value = NewNode(op, receiver, home_object, name_node); + Node* language = jsgraph()->Constant(language_mode()); + const Operator* op = javascript()->CallRuntime(Runtime::kLoadFromSuper, 4); + Node* value = NewNode(op, receiver, home_object, name_node, language); return Record(js_type_feedback_, value, feedback.slot()); } @@ -3503,9 +3504,10 @@ Node* AstGraphBuilder::BuildNamedSuperLoad( Node* AstGraphBuilder::BuildKeyedSuperLoad( Node* receiver, Node* home_object, Node* key, const ResolvedFeedbackSlot& feedback) { + Node* language = jsgraph()->Constant(language_mode()); const Operator* op = - javascript()->CallRuntime(Runtime::kLoadKeyedFromSuper, 3); - Node* value = NewNode(op, receiver, home_object, key); + javascript()->CallRuntime(Runtime::kLoadKeyedFromSuper, 4); + Node* value = NewNode(op, receiver, home_object, key, language); return Record(js_type_feedback_, value, feedback.slot()); } diff --git a/src/compiler/js-generic-lowering.cc b/src/compiler/js-generic-lowering.cc index 9132a39..f3863d6 100644 --- a/src/compiler/js-generic-lowering.cc +++ b/src/compiler/js-generic-lowering.cc @@ -314,8 +314,8 @@ void JSGenericLowering::LowerJSToObject(Node* node) { void JSGenericLowering::LowerJSLoadProperty(Node* node) { CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); const LoadPropertyParameters& p = LoadPropertyParametersOf(node->op()); - Callable callable = - CodeFactory::KeyedLoadICInOptimizedCode(isolate(), UNINITIALIZED); + Callable callable = CodeFactory::KeyedLoadICInOptimizedCode( + isolate(), p.language_mode(), UNINITIALIZED); node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index())); ReplaceWithStubCall(node, callable, flags); } @@ -325,7 +325,7 @@ void JSGenericLowering::LowerJSLoadNamed(Node* node) { CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); const LoadNamedParameters& p = LoadNamedParametersOf(node->op()); Callable callable = CodeFactory::LoadICInOptimizedCode( - isolate(), p.contextual_mode(), UNINITIALIZED); + isolate(), p.contextual_mode(), p.language_mode(), UNINITIALIZED); node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.name())); node->InsertInput(zone(), 2, jsgraph()->SmiConstant(p.feedback().index())); ReplaceWithStubCall(node, callable, flags); diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc index 83bf557..8a2c6fe 100644 --- a/src/compiler/js-operator.cc +++ b/src/compiler/js-operator.cc @@ -190,6 +190,7 @@ size_t hash_value(ResolvedFeedbackSlot const& p) { bool operator==(LoadNamedParameters const& lhs, LoadNamedParameters const& rhs) { return lhs.name() == rhs.name() && + lhs.language_mode() == rhs.language_mode() && lhs.contextual_mode() == rhs.contextual_mode() && lhs.feedback() == rhs.feedback(); } @@ -202,24 +203,26 @@ bool operator!=(LoadNamedParameters const& lhs, size_t hash_value(LoadNamedParameters const& p) { - return base::hash_combine(p.name(), p.contextual_mode(), p.feedback()); + return base::hash_combine(p.name(), p.language_mode(), p.contextual_mode(), + p.feedback()); } std::ostream& operator<<(std::ostream& os, LoadNamedParameters const& p) { - return os << Brief(*p.name().handle()) << ", " << p.contextual_mode(); + return os << Brief(*p.name().handle()) << ", " << p.language_mode() << ", " + << p.contextual_mode(); } std::ostream& operator<<(std::ostream& os, LoadPropertyParameters const& p) { - // Nothing special to print. - return os; + return os << p.language_mode(); } bool operator==(LoadPropertyParameters const& lhs, LoadPropertyParameters const& rhs) { - return lhs.feedback() == rhs.feedback(); + return lhs.language_mode() == rhs.language_mode() && + lhs.feedback() == rhs.feedback(); } @@ -236,7 +239,7 @@ const LoadPropertyParameters& LoadPropertyParametersOf(const Operator* op) { size_t hash_value(LoadPropertyParameters const& p) { - return hash_value(p.feedback()); + return base::hash_combine(p.language_mode(), p.feedback()); } @@ -459,8 +462,9 @@ const Operator* JSOperatorBuilder::CallConstruct(int arguments) { const Operator* JSOperatorBuilder::LoadNamed( const Unique& name, const ResolvedFeedbackSlot& feedback, - ContextualMode contextual_mode) { - LoadNamedParameters parameters(name, feedback, contextual_mode); + LanguageMode language_mode, ContextualMode contextual_mode) { + LoadNamedParameters parameters(name, feedback, language_mode, + contextual_mode); return new (zone()) Operator1( // -- IrOpcode::kJSLoadNamed, Operator::kNoProperties, // opcode "JSLoadNamed", // name @@ -470,8 +474,8 @@ const Operator* JSOperatorBuilder::LoadNamed( const Operator* JSOperatorBuilder::LoadProperty( - const ResolvedFeedbackSlot& feedback) { - LoadPropertyParameters parameters(feedback); + const ResolvedFeedbackSlot& feedback, LanguageMode language_mode) { + LoadPropertyParameters parameters(feedback, language_mode); return new (zone()) Operator1( // -- IrOpcode::kJSLoadProperty, Operator::kNoProperties, // opcode "JSLoadProperty", // name diff --git a/src/compiler/js-operator.h b/src/compiler/js-operator.h index e9545c9..40c5f7d 100644 --- a/src/compiler/js-operator.h +++ b/src/compiler/js-operator.h @@ -223,10 +223,15 @@ class LoadNamedParameters final { public: LoadNamedParameters(const Unique& name, const ResolvedFeedbackSlot& feedback, + LanguageMode language_mode, ContextualMode contextual_mode) - : name_(name), feedback_(feedback), contextual_mode_(contextual_mode) {} + : name_(name), + feedback_(feedback), + language_mode_(language_mode), + contextual_mode_(contextual_mode) {} const Unique& name() const { return name_; } + LanguageMode language_mode() const { return language_mode_; } ContextualMode contextual_mode() const { return contextual_mode_; } const ResolvedFeedbackSlot& feedback() const { return feedback_; } @@ -234,6 +239,7 @@ class LoadNamedParameters final { private: const Unique name_; const ResolvedFeedbackSlot feedback_; + const LanguageMode language_mode_; const ContextualMode contextual_mode_; }; @@ -251,13 +257,17 @@ const LoadNamedParameters& LoadNamedParametersOf(const Operator* op); // used as a parameter by JSLoadProperty operators. class LoadPropertyParameters final { public: - explicit LoadPropertyParameters(const ResolvedFeedbackSlot& feedback) - : feedback_(feedback) {} + explicit LoadPropertyParameters(const ResolvedFeedbackSlot& feedback, + LanguageMode language_mode) + : feedback_(feedback), language_mode_(language_mode) {} const ResolvedFeedbackSlot& feedback() const { return feedback_; } + LanguageMode language_mode() const { return language_mode_; } + private: const ResolvedFeedbackSlot feedback_; + const LanguageMode language_mode_; }; bool operator==(LoadPropertyParameters const&, LoadPropertyParameters const&); @@ -368,9 +378,11 @@ class JSOperatorBuilder final : public ZoneObject { const Operator* CallConstruct(int arguments); - const Operator* LoadProperty(const ResolvedFeedbackSlot& feedback); + const Operator* LoadProperty(const ResolvedFeedbackSlot& feedback, + LanguageMode language_mode); const Operator* LoadNamed(const Unique& name, const ResolvedFeedbackSlot& feedback, + LanguageMode language_mode, ContextualMode contextual_mode = NOT_CONTEXTUAL); const Operator* StoreProperty(LanguageMode language_mode); diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index 94fae66..4a5ab67 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -1025,8 +1025,8 @@ Reduction JSTypedLowering::ReduceJSLoadDynamicGlobal(Node* node) { javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true), context, context, effect); Node* fast = graph()->NewNode( - javascript()->LoadNamed(name, access.feedback(), access.mode()), global, - vector, context, state1, state2, global, check_true); + javascript()->LoadNamed(name, access.feedback(), SLOPPY, access.mode()), + global, vector, context, state1, state2, global, check_true); // Slow case, because variable potentially shadowed. Perform dynamic lookup. uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired; diff --git a/src/full-codegen.cc b/src/full-codegen.cc index f1b3904..5860da8 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -469,8 +469,10 @@ void FullCodeGenerator::PrepareForBailout(Expression* node, State state) { void FullCodeGenerator::CallLoadIC(ContextualMode contextual_mode, + LanguageMode language_mode, TypeFeedbackId id) { - Handle ic = CodeFactory::LoadIC(isolate(), contextual_mode).code(); + Handle ic = + CodeFactory::LoadIC(isolate(), contextual_mode, language_mode).code(); CallIC(ic, id); } diff --git a/src/full-codegen.h b/src/full-codegen.h index 4492434..3cc400a 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -683,7 +683,7 @@ class FullCodeGenerator: public AstVisitor { void CallIC(Handle code, TypeFeedbackId id = TypeFeedbackId::None()); - void CallLoadIC(ContextualMode mode, + void CallLoadIC(ContextualMode mode, LanguageMode language_mode = SLOPPY, TypeFeedbackId id = TypeFeedbackId::None()); void CallGlobalLoadIC(Handle name); void CallStoreIC(TypeFeedbackId id = TypeFeedbackId::None()); diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 15aa385..bdb4a6b 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -6392,8 +6392,9 @@ class HLoadNamedField final : public HTemplateInstruction<2> { class HLoadNamedGeneric final : public HTemplateInstruction<2> { public: - DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadNamedGeneric, HValue*, - Handle, InlineCacheState); + DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadNamedGeneric, HValue*, + Handle, LanguageMode, + InlineCacheState); HValue* context() const { return OperandAt(0); } HValue* object() const { return OperandAt(1); } @@ -6421,11 +6422,15 @@ class HLoadNamedGeneric final : public HTemplateInstruction<2> { DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric) + LanguageMode language_mode() const { return language_mode_; } + private: HLoadNamedGeneric(HValue* context, HValue* object, Handle name, + LanguageMode language_mode, InlineCacheState initialization_state) : name_(name), slot_(FeedbackVectorICSlot::Invalid()), + language_mode_(language_mode), initialization_state_(initialization_state) { SetOperandAt(0, context); SetOperandAt(1, object); @@ -6436,6 +6441,7 @@ class HLoadNamedGeneric final : public HTemplateInstruction<2> { Handle name_; Handle feedback_vector_; FeedbackVectorICSlot slot_; + LanguageMode language_mode_; InlineCacheState initialization_state_; }; @@ -6675,8 +6681,9 @@ class HLoadKeyed final : public HTemplateInstruction<3>, class HLoadKeyedGeneric final : public HTemplateInstruction<3> { public: - DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadKeyedGeneric, HValue*, - HValue*, InlineCacheState); + DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadKeyedGeneric, HValue*, + HValue*, LanguageMode, + InlineCacheState); HValue* object() const { return OperandAt(0); } HValue* key() const { return OperandAt(1); } HValue* context() const { return OperandAt(2); } @@ -6708,11 +6715,15 @@ class HLoadKeyedGeneric final : public HTemplateInstruction<3> { DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric) + LanguageMode language_mode() const { return language_mode_; } + private: HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key, + LanguageMode language_mode, InlineCacheState initialization_state) : slot_(FeedbackVectorICSlot::Invalid()), - initialization_state_(initialization_state) { + initialization_state_(initialization_state), + language_mode_(language_mode) { set_representation(Representation::Tagged()); SetOperandAt(0, obj); SetOperandAt(1, key); @@ -6723,6 +6734,7 @@ class HLoadKeyedGeneric final : public HTemplateInstruction<3> { Handle feedback_vector_; FeedbackVectorICSlot slot_; InlineCacheState initialization_state_; + LanguageMode language_mode_; }; diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 2a0011f..d1959bb 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -683,6 +683,11 @@ HConstant* HGraph::GetConstantMinus1() { } +HConstant* HGraph::GetConstantBool(bool value) { + return value ? GetConstantTrue() : GetConstantFalse(); +} + + #define DEFINE_GET_CONSTANT(Name, name, type, htype, boolean_value) \ HConstant* HGraph::GetConstant##Name() { \ if (!constant_##name##_.is_set()) { \ @@ -1667,10 +1672,9 @@ HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) { } -HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, - HValue* elements, - HValue* key, - HValue* hash) { +HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad( + HValue* receiver, HValue* elements, HValue* key, HValue* hash, + LanguageMode language_mode) { HValue* capacity = Add(elements, Add(NameDictionary::kCapacityIndex), nullptr, FAST_ELEMENTS); @@ -1712,10 +1716,10 @@ HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, { // element == undefined means "not found". Call the runtime. // TODO(jkummerow): walk the prototype chain instead. - Add(receiver, key); + Add(receiver, key, Add(language_mode)); Push(Add(isolate()->factory()->empty_string(), Runtime::FunctionForId(Runtime::kKeyedGetProperty), - 2)); + 3)); } if_undefined.Else(); { @@ -1772,10 +1776,10 @@ HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, result_index->ClearFlag(HValue::kCanOverflow); Push(Add(elements, result_index, nullptr, FAST_ELEMENTS)); details_compare.Else(); - Add(receiver, key); + Add(receiver, key, Add(language_mode)); Push(Add(isolate()->factory()->empty_string(), Runtime::FunctionForId(Runtime::kKeyedGetProperty), - 2)); + 3)); details_compare.End(); found_key_match.Else(); @@ -6223,7 +6227,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { if (IsFound()) return IsLoad() || !IsReadOnly(); if (IsIntegerIndexedExotic()) return false; if (!LookupInPrototypes()) return false; - if (IsLoad()) return true; + if (IsLoad()) return !is_strong(builder_->function_language_mode()); if (IsAccessorConstant()) return true; LookupTransition(*map_, *name_, NONE); @@ -7041,14 +7045,14 @@ HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( // use a generic Keyed Load if we are using the type vector, because // it has to share information with full code. HConstant* key = Add(name); - HLoadKeyedGeneric* result = - New(object, key, PREMONOMORPHIC); + HLoadKeyedGeneric* result = New( + object, key, function_language_mode(), PREMONOMORPHIC); result->SetVectorAndSlot(vector, slot); return result; } - HLoadNamedGeneric* result = - New(object, name, PREMONOMORPHIC); + HLoadNamedGeneric* result = New( + object, name, function_language_mode(), PREMONOMORPHIC); result->SetVectorAndSlot(vector, slot); return result; } else { @@ -7067,8 +7071,8 @@ HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric( HValue* value) { if (access_type == LOAD) { InlineCacheState initial_state = expr->AsProperty()->GetInlineCacheState(); - HLoadKeyedGeneric* result = - New(object, key, initial_state); + HLoadKeyedGeneric* result = New( + object, key, function_language_mode(), initial_state); // HLoadKeyedGeneric with vector ics benefits from being encoded as // MEGAMORPHIC because the vector/slot combo becomes unnecessary. if (initial_state != MEGAMORPHIC) { diff --git a/src/hydrogen.h b/src/hydrogen.h index 48e333f..acde9f0 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -331,6 +331,7 @@ class HGraph final : public ZoneObject { HConstant* GetConstantMinus1(); HConstant* GetConstantTrue(); HConstant* GetConstantFalse(); + HConstant* GetConstantBool(bool value); HConstant* GetConstantHole(); HConstant* GetConstantNull(); HConstant* GetInvalidContext(); @@ -1352,9 +1353,9 @@ class HGraphBuilder { HValue* key); HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver, - HValue* elements, - HValue* key, - HValue* hash); + HValue* elements, HValue* key, + HValue* hash, + LanguageMode language_mode); HValue* BuildRegExpConstructResult(HValue* length, HValue* index, diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 7435ccd..8ae0fed 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -4430,7 +4430,7 @@ void LoadICTrampolineStub::Generate(MacroAssembler* masm) { void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { EmitLoadTypeFeedbackVector(masm, LoadWithVectorDescriptor::VectorRegister()); - KeyedLoadICStub stub(isolate()); + KeyedLoadICStub stub(isolate(), state()); stub.GenerateForTrampoline(masm); } @@ -4634,7 +4634,7 @@ void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); __ j(not_equal, &try_poly_name); Handle megamorphic_stub = - KeyedLoadIC::ChooseMegamorphicStub(masm->isolate()); + KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); __ jmp(megamorphic_stub, RelocInfo::CODE_TARGET); __ bind(&try_poly_name); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index f27dd21..1fd2cb9 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -2166,7 +2166,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ mov(load_receiver, Operand(esp, kPointerSize)); __ mov(LoadDescriptor::SlotRegister(), Immediate(SmiFromSlot(expr->KeyedLoadFeedbackSlot()))); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code(); CallIC(ic, TypeFeedbackId::None()); __ mov(edi, eax); __ mov(Operand(esp, 2 * kPointerSize), edi); @@ -2335,7 +2335,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { __ mov(LoadDescriptor::NameRegister(), Immediate(key->value())); __ mov(LoadDescriptor::SlotRegister(), Immediate(SmiFromSlot(prop->PropertyFeedbackSlot()))); - CallLoadIC(NOT_CONTEXTUAL); + CallLoadIC(NOT_CONTEXTUAL, language_mode()); } @@ -2347,13 +2347,14 @@ void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { DCHECK(prop->IsSuperAccess()); __ push(Immediate(key->value())); - __ CallRuntime(Runtime::kLoadFromSuper, 3); + __ push(Immediate(Smi::FromInt(language_mode()))); + __ CallRuntime(Runtime::kLoadFromSuper, 4); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code(); __ mov(LoadDescriptor::SlotRegister(), Immediate(SmiFromSlot(prop->PropertyFeedbackSlot()))); CallIC(ic); @@ -2362,9 +2363,10 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { // Stack: receiver, home_object, key. + __ push(Immediate(Smi::FromInt(language_mode()))); SetSourcePosition(prop->position()); - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); } @@ -2894,13 +2896,15 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { __ push(eax); __ push(Operand(esp, kPointerSize * 2)); __ push(Immediate(key->value())); + __ push(Immediate(Smi::FromInt(language_mode()))); // Stack here: // - home_object // - this (receiver) // - this (receiver) <-- LoadFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadFromSuper, 4); // Replace home_object with target function. __ mov(Operand(esp, kPointerSize), eax); @@ -2950,13 +2954,15 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { __ push(eax); __ push(Operand(esp, kPointerSize * 2)); VisitForStackValue(prop->key()); + __ push(Immediate(Smi::FromInt(language_mode()))); // Stack here: // - home_object // - this (receiver) // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); // Replace home_object with target function. __ mov(Operand(esp, kPointerSize), eax); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index ba601db..3348c9f 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -2836,7 +2836,7 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { __ mov(LoadDescriptor::NameRegister(), instr->name()); EmitVectorLoadICRegisters(instr); ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; - Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, + Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, SLOPPY, PREMONOMORPHIC).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -2952,9 +2952,10 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { __ mov(LoadDescriptor::NameRegister(), instr->name()); EmitVectorLoadICRegisters(instr); - Handle ic = CodeFactory::LoadICInOptimizedCode( - isolate(), NOT_CONTEXTUAL, - instr->hydrogen()->initialization_state()).code(); + Handle ic = + CodeFactory::LoadICInOptimizedCode( + isolate(), NOT_CONTEXTUAL, instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3196,9 +3197,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { EmitVectorLoadICRegisters(instr); } - Handle ic = - CodeFactory::KeyedLoadICInOptimizedCode( - isolate(), instr->hydrogen()->initialization_state()).code(); + Handle ic = CodeFactory::KeyedLoadICInOptimizedCode( + isolate(), instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/src/ic/arm/handler-compiler-arm.cc b/src/ic/arm/handler-compiler-arm.cc index 6af65e2..86eddde 100644 --- a/src/ic/arm/handler-compiler-arm.cc +++ b/src/ic/arm/handler-compiler-arm.cc @@ -16,6 +16,30 @@ namespace internal { #define __ ACCESS_MASM(masm) +void NamedLoadHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Push receiver and key for runtime call. + __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); + + // The slow case calls into the runtime to complete the load without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + +void ElementHandlerCompiler::GenerateLoadSlow(MacroAssembler* masm) { + // Push receiver and key for runtime call. + __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); + + // The slow case calls into the runtime to complete the load without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kKeyedLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + void NamedLoadHandlerCompiler::GenerateLoadViaGetter( MacroAssembler* masm, Handle map, Register receiver, Register holder, int accessor_index, int expected_arguments, Register scratch) { diff --git a/src/ic/arm/ic-arm.cc b/src/ic/arm/ic-arm.cc index 3ecdc31..e61555a 100644 --- a/src/ic/arm/ic-arm.cc +++ b/src/ic/arm/ic-arm.cc @@ -161,7 +161,8 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, Register key, Register elements, Register scratch1, Register scratch2, - Register result, Label* slow) { + Register result, Label* slow, + LanguageMode language_mode) { // Register use: // // receiver - holds the receiver on entry. @@ -183,7 +184,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, // // scratch2 - used to hold maps, prototypes, and the loaded value. Label check_prototypes, check_next_prototype; - Label done, in_bounds, return_undefined; + Label done, in_bounds, absent; __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); __ AssertFastElements(elements); @@ -202,7 +203,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ ldr(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset)); // scratch2: current prototype __ CompareRoot(scratch2, Heap::kNullValueRootIndex); - __ b(eq, &return_undefined); + __ b(eq, &absent); __ ldr(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset)); __ ldr(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset)); // elements: elements of current prototype @@ -217,9 +218,14 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ b(ne, slow); __ jmp(&check_next_prototype); - __ bind(&return_undefined); - __ LoadRoot(result, Heap::kUndefinedValueRootIndex); - __ jmp(&done); + __ bind(&absent); + if (is_strong(language_mode)) { + // Strong mode accesses must throw in this case, so call the runtime. + __ jmp(slow); + } else { + __ LoadRoot(result, Heap::kUndefinedValueRootIndex); + __ jmp(&done); + } __ bind(&in_bounds); // Fast case: Do the load. @@ -278,7 +284,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { // Dictionary load failed, go slow (but don't miss). __ bind(&slow); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); } @@ -313,13 +319,17 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { } -void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void LoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is in lr. __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister()); __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister()); - __ TailCallRuntime(Runtime::kGetProperty, 2, 1); + // Perform tail call to the entry. + ExternalReference ref = + ExternalReference(IC_Utility(kLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } @@ -341,16 +351,21 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { } -void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void KeyedLoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is in lr. __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); - __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); + // Perform tail call to the entry. + ExternalReference ref = + ExternalReference(IC_Utility(kKeyedLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } -void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { +void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm, + LanguageMode language_mode) { // The return address is in lr. Label slow, check_name, index_smi, index_name, property_array_property; Label probe_dictionary, check_number_dictionary; @@ -374,7 +389,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { // Check the receiver's map to see if it has fast elements. __ CheckFastElements(r0, r3, &check_number_dictionary); - GenerateFastArrayLoad(masm, receiver, key, r0, r3, r4, r0, &slow); + GenerateFastArrayLoad(masm, receiver, key, r0, r3, r4, r0, &slow, + language_mode); __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r4, r3); __ Ret(); @@ -396,7 +412,7 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { __ bind(&slow); __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1, r4, r3); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); __ bind(&check_name); GenerateKeyNameCheck(masm, key, r0, r3, &index_name, &slow); diff --git a/src/ic/arm64/handler-compiler-arm64.cc b/src/ic/arm64/handler-compiler-arm64.cc index 3986c0e..5d1c8e2 100644 --- a/src/ic/arm64/handler-compiler-arm64.cc +++ b/src/ic/arm64/handler-compiler-arm64.cc @@ -267,6 +267,30 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( } +void NamedLoadHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Push receiver and key for runtime call. + __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); + + // The slow case calls into the runtime to complete the load without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + +void ElementHandlerCompiler::GenerateLoadSlow(MacroAssembler* masm) { + // Push receiver and key for runtime call. + __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); + + // The slow case calls into the runtime to complete the load without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kKeyedLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + void NamedLoadHandlerCompiler::GenerateLoadViaGetter( MacroAssembler* masm, Handle map, Register receiver, Register holder, int accessor_index, int expected_arguments, Register scratch) { diff --git a/src/ic/arm64/ic-arm64.cc b/src/ic/arm64/ic-arm64.cc index e0bf48b..e513845 100644 --- a/src/ic/arm64/ic-arm64.cc +++ b/src/ic/arm64/ic-arm64.cc @@ -167,11 +167,12 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, Register key, Register elements, Register scratch1, Register scratch2, - Register result, Label* slow) { + Register result, Label* slow, + LanguageMode language_mode) { DCHECK(!AreAliased(receiver, key, elements, scratch1, scratch2)); Label check_prototypes, check_next_prototype; - Label done, in_bounds, return_undefined; + Label done, in_bounds, absent; // Check for fast array. __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); @@ -191,7 +192,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ Bind(&check_next_prototype); __ Ldr(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset)); // scratch2: current prototype - __ JumpIfRoot(scratch2, Heap::kNullValueRootIndex, &return_undefined); + __ JumpIfRoot(scratch2, Heap::kNullValueRootIndex, &absent); __ Ldr(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset)); __ Ldr(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset)); // elements: elements of current prototype @@ -204,9 +205,14 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ JumpIfNotRoot(elements, Heap::kEmptyFixedArrayRootIndex, slow); __ B(&check_next_prototype); - __ Bind(&return_undefined); - __ LoadRoot(result, Heap::kUndefinedValueRootIndex); - __ B(&done); + __ Bind(&absent); + if (is_strong(language_mode)) { + // Strong mode accesses must throw in this case, so call the runtime. + __ B(slow); + } else { + __ LoadRoot(result, Heap::kUndefinedValueRootIndex); + __ B(&done); + } __ Bind(&in_bounds); // Fast case: Do the load. @@ -272,7 +278,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { // Dictionary load failed, go slow (but don't miss). __ Bind(&slow); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); } @@ -296,10 +302,15 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { } -void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void LoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is in lr. __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); - __ TailCallRuntime(Runtime::kGetProperty, 2, 1); + + // Perform tail call to the entry. + ExternalReference ref = + ExternalReference(IC_Utility(kLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } @@ -324,10 +335,15 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { } -void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void KeyedLoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is in lr. __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); - __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); + + // Perform tail call to the entry. + ExternalReference ref = + ExternalReference(IC_Utility(kKeyedLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } @@ -335,7 +351,8 @@ static void GenerateKeyedLoadWithSmiKey(MacroAssembler* masm, Register key, Register receiver, Register scratch1, Register scratch2, Register scratch3, Register scratch4, Register scratch5, - Label* slow) { + Label* slow, + LanguageMode language_mode) { DCHECK(!AreAliased(key, receiver, scratch1, scratch2, scratch3, scratch4, scratch5)); @@ -351,7 +368,7 @@ static void GenerateKeyedLoadWithSmiKey(MacroAssembler* masm, Register key, __ CheckFastElements(scratch1, scratch2, &check_number_dictionary); GenerateFastArrayLoad(masm, receiver, key, scratch3, scratch2, scratch1, - result, slow); + result, slow, language_mode); __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, scratch1, scratch2); __ Ret(); @@ -422,7 +439,8 @@ static void GenerateKeyedLoadWithNameKey(MacroAssembler* masm, Register key, } -void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { +void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm, + LanguageMode language_mode) { // The return address is in lr. Label slow, check_name, index_smi, index_name; @@ -435,13 +453,14 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { __ Bind(&index_smi); // Now the key is known to be a smi. This place is also jumped to from below // where a numeric string is converted to a smi. - GenerateKeyedLoadWithSmiKey(masm, key, receiver, x7, x3, x4, x5, x6, &slow); + GenerateKeyedLoadWithSmiKey(masm, key, receiver, x7, x3, x4, x5, x6, &slow, + language_mode); // Slow case. __ Bind(&slow); __ IncrementCounter(masm->isolate()->counters()->keyed_load_generic_slow(), 1, x4, x3); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); __ Bind(&check_name); GenerateKeyNameCheck(masm, key, x0, x3, &index_name, &slow); diff --git a/src/ic/handler-compiler.cc b/src/ic/handler-compiler.cc index 04b8fb0..99c9c15 100644 --- a/src/ic/handler-compiler.cc +++ b/src/ic/handler-compiler.cc @@ -537,7 +537,8 @@ Handle NamedStoreHandlerCompiler::CompileStoreCallback( void ElementHandlerCompiler::CompileElementHandlers( - MapHandleList* receiver_maps, CodeHandleList* handlers) { + MapHandleList* receiver_maps, CodeHandleList* handlers, + LanguageMode language_mode) { for (int i = 0; i < receiver_maps->length(); ++i) { Handle receiver_map = receiver_maps->at(i); Handle cached_stub; @@ -553,8 +554,10 @@ void ElementHandlerCompiler::CompileElementHandlers( // No need to check for an elements-free prototype chain here, the // generated stub code needs to check that dynamically anyway. bool convert_hole_to_undefined = - is_js_array && elements_kind == FAST_HOLEY_ELEMENTS && - *receiver_map == isolate()->get_initial_js_array_map(elements_kind); + (is_js_array && elements_kind == FAST_HOLEY_ELEMENTS && + *receiver_map == + isolate()->get_initial_js_array_map(elements_kind)) && + !is_strong(language_mode); if (receiver_map->has_indexed_interceptor()) { cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode(); @@ -567,7 +570,9 @@ void ElementHandlerCompiler::CompileElementHandlers( convert_hole_to_undefined).GetCode(); } else { DCHECK(elements_kind == DICTIONARY_ELEMENTS); - cached_stub = LoadDictionaryElementStub(isolate()).GetCode(); + LoadICState state = LoadICState( + is_strong(language_mode) ? LoadICState::kStrongModeState : 0); + cached_stub = LoadDictionaryElementStub(isolate(), state).GetCode(); } } diff --git a/src/ic/handler-compiler.h b/src/ic/handler-compiler.h index 077db92..66fdf56 100644 --- a/src/ic/handler-compiler.h +++ b/src/ic/handler-compiler.h @@ -146,6 +146,8 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler { static Handle ComputeLoadNonexistent(Handle name, Handle map); + static void GenerateSlow(MacroAssembler* masm); + static void GenerateLoadViaGetter(MacroAssembler* masm, Handle map, Register receiver, Register holder, int accessor_index, int expected_arguments, @@ -290,8 +292,10 @@ class ElementHandlerCompiler : public PropertyHandlerCompiler { virtual ~ElementHandlerCompiler() {} void CompileElementHandlers(MapHandleList* receiver_maps, - CodeHandleList* handlers); + CodeHandleList* handlers, + LanguageMode language_mode); + static void GenerateLoadSlow(MacroAssembler* masm); static void GenerateStoreSlow(MacroAssembler* masm); }; } diff --git a/src/ic/ia32/handler-compiler-ia32.cc b/src/ic/ia32/handler-compiler-ia32.cc index 8f5200a..57a478e 100644 --- a/src/ic/ia32/handler-compiler-ia32.cc +++ b/src/ic/ia32/handler-compiler-ia32.cc @@ -16,6 +16,39 @@ namespace internal { #define __ ACCESS_MASM(masm) +static void LoadIC_PushArgs(MacroAssembler* masm) { + Register receiver = LoadDescriptor::ReceiverRegister(); + Register name = LoadDescriptor::NameRegister(); + + DCHECK(!ebx.is(receiver) && !ebx.is(name)); + + __ pop(ebx); + __ push(receiver); + __ push(name); + __ push(ebx); +} + + +void NamedLoadHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Return address is on the stack. + LoadIC_PushArgs(masm); + + // Do tail-call to runtime routine. + ExternalReference ref(IC_Utility(IC::kLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + +void ElementHandlerCompiler::GenerateLoadSlow(MacroAssembler* masm) { + // Return address is on the stack. + LoadIC_PushArgs(masm); + + // Do tail-call to runtime routine. + ExternalReference ref(IC_Utility(IC::kKeyedLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + void NamedLoadHandlerCompiler::GenerateLoadViaGetter( MacroAssembler* masm, Handle map, Register receiver, Register holder, int accessor_index, int expected_arguments, Register scratch) { diff --git a/src/ic/ia32/ic-ia32.cc b/src/ic/ia32/ic-ia32.cc index 6d54b07..4f8ee08 100644 --- a/src/ic/ia32/ic-ia32.cc +++ b/src/ic/ia32/ic-ia32.cc @@ -172,7 +172,7 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, Register key, Register scratch, Register scratch2, Register result, - Label* slow) { + Label* slow, LanguageMode language_mode) { // Register use: // receiver - holds the receiver and is unchanged. // key - holds the key and is unchanged (must be a smi). @@ -182,7 +182,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, // result - holds the result on exit if the load succeeds and // we fall through. Label check_prototypes, check_next_prototype; - Label done, in_bounds, return_undefined; + Label done, in_bounds, absent; __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset)); __ AssertFastElements(scratch); @@ -200,7 +200,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ mov(scratch2, FieldOperand(scratch2, Map::kPrototypeOffset)); // scratch2: current prototype __ cmp(scratch2, masm->isolate()->factory()->null_value()); - __ j(equal, &return_undefined); + __ j(equal, &absent); __ mov(scratch, FieldOperand(scratch2, JSObject::kElementsOffset)); __ mov(scratch2, FieldOperand(scratch2, HeapObject::kMapOffset)); // scratch: elements of current prototype @@ -215,9 +215,14 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ j(not_equal, slow); __ jmp(&check_next_prototype); - __ bind(&return_undefined); - __ mov(result, masm->isolate()->factory()->undefined_value()); - __ jmp(&done); + __ bind(&absent); + if (is_strong(language_mode)) { + // Strong mode accesses must throw in this case, so call the runtime. + __ jmp(slow); + } else { + __ mov(result, masm->isolate()->factory()->undefined_value()); + __ jmp(&done); + } __ bind(&in_bounds); // Fast case: Do the load. @@ -263,7 +268,8 @@ static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, } -void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { +void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm, + LanguageMode language_mode) { // The return address is on the stack. Label slow, check_name, index_smi, index_name, property_array_property; Label probe_dictionary, check_number_dictionary; @@ -285,7 +291,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { // Check the receiver's map to see if it has fast elements. __ CheckFastElements(eax, &check_number_dictionary); - GenerateFastArrayLoad(masm, receiver, key, eax, ebx, eax, &slow); + GenerateFastArrayLoad(masm, receiver, key, eax, ebx, eax, &slow, + language_mode); Isolate* isolate = masm->isolate(); Counters* counters = isolate->counters(); __ IncrementCounter(counters->keyed_load_generic_smi(), 1); @@ -317,7 +324,7 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { __ bind(&slow); // Slow case: jump to runtime. __ IncrementCounter(counters->keyed_load_generic_slow(), 1); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); __ bind(&check_name); GenerateKeyNameCheck(masm, key, eax, ebx, &index_name, &slow); @@ -623,7 +630,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { // Dictionary load failed, go slow (but don't miss). __ bind(&slow); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); } @@ -658,7 +665,7 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { } -void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void LoadIC::GenerateSlow(MacroAssembler* masm) { // Return address is on the stack. Register receiver = LoadDescriptor::ReceiverRegister(); Register name = LoadDescriptor::NameRegister(); @@ -670,7 +677,10 @@ void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { __ push(ebx); // Perform tail call to the entry. - __ TailCallRuntime(Runtime::kGetProperty, 2, 1); + ExternalReference ref = + ExternalReference(IC_Utility(kLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } @@ -688,7 +698,7 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { } -void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void KeyedLoadIC::GenerateSlow(MacroAssembler* masm) { // Return address is on the stack. Register receiver = LoadDescriptor::ReceiverRegister(); Register name = LoadDescriptor::NameRegister(); @@ -700,7 +710,10 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { __ push(ebx); // Perform tail call to the entry. - __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); + ExternalReference ref = + ExternalReference(IC_Utility(kKeyedLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } diff --git a/src/ic/ic-compiler.cc b/src/ic/ic-compiler.cc index dee91ff..0794342 100644 --- a/src/ic/ic-compiler.cc +++ b/src/ic/ic-compiler.cc @@ -88,7 +88,7 @@ Handle PropertyICCompiler::ComputeMonomorphic( Handle PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( - Handle receiver_map) { + Handle receiver_map, ExtraICState extra_ic_state) { Isolate* isolate = receiver_map->GetIsolate(); bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; ElementsKind elements_kind = receiver_map->elements_kind(); @@ -97,8 +97,8 @@ Handle PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( // stub code needs to check that dynamically anyway. bool convert_hole_to_undefined = is_js_array && elements_kind == FAST_HOLEY_ELEMENTS && - *receiver_map == isolate->get_initial_js_array_map(elements_kind); - + *receiver_map == isolate->get_initial_js_array_map(elements_kind) && + !(is_strong(LoadICState::GetLanguageMode(extra_ic_state))); Handle stub; if (receiver_map->has_indexed_interceptor()) { stub = LoadIndexedInterceptorStub(isolate).GetCode(); @@ -113,7 +113,8 @@ Handle PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( stub = LoadFastElementStub(isolate, is_js_array, elements_kind, convert_hole_to_undefined).GetCode(); } else { - stub = LoadDictionaryElementStub(isolate).GetCode(); + stub = LoadDictionaryElementStub(isolate, LoadICState(extra_ic_state)) + .GetCode(); } return stub; } @@ -221,7 +222,7 @@ Handle PropertyICCompiler::ComputeCompareNil(Handle receiver_map, Handle PropertyICCompiler::ComputeKeyedLoadPolymorphic( - MapHandleList* receiver_maps) { + MapHandleList* receiver_maps, LanguageMode language_mode) { Isolate* isolate = receiver_maps->at(0)->GetIsolate(); DCHECK(KeyedLoadIC::GetKeyType(kNoExtraICState) == ELEMENT); Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC); @@ -232,7 +233,7 @@ Handle PropertyICCompiler::ComputeKeyedLoadPolymorphic( CodeHandleList handlers(receiver_maps->length()); ElementHandlerCompiler compiler(isolate); - compiler.CompileElementHandlers(receiver_maps, &handlers); + compiler.CompileElementHandlers(receiver_maps, &handlers, language_mode); PropertyICCompiler ic_compiler(isolate, Code::KEYED_LOAD_IC); Handle code = ic_compiler.CompilePolymorphic( receiver_maps, &handlers, isolate->factory()->empty_string(), diff --git a/src/ic/ic-compiler.h b/src/ic/ic-compiler.h index 47dfe08..b5226e9 100644 --- a/src/ic/ic-compiler.h +++ b/src/ic/ic-compiler.h @@ -32,12 +32,13 @@ class PropertyICCompiler : public PropertyAccessCompiler { // Keyed static Handle ComputeKeyedLoadMonomorphicHandler( - Handle receiver_map); + Handle receiver_map, ExtraICState extra_ic_state); static Handle ComputeKeyedStoreMonomorphic( Handle receiver_map, LanguageMode language_mode, KeyedAccessStoreMode store_mode); - static Handle ComputeKeyedLoadPolymorphic(MapHandleList* receiver_maps); + static Handle ComputeKeyedLoadPolymorphic(MapHandleList* receiver_maps, + LanguageMode language_mode); static Handle ComputeKeyedStorePolymorphic( MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode, LanguageMode language_mode); diff --git a/src/ic/ic-inl.h b/src/ic/ic-inl.h index 55572f7..657f0b6 100644 --- a/src/ic/ic-inl.h +++ b/src/ic/ic-inl.h @@ -135,6 +135,9 @@ void LoadIC::set_target(Code* code) { // The contextual mode must be preserved across IC patching. DCHECK(LoadICState::GetContextualMode(code->extra_ic_state()) == LoadICState::GetContextualMode(target()->extra_ic_state())); + // Strongness must be preserved across IC patching. + DCHECK(LoadICState::GetLanguageMode(code->extra_ic_state()) == + LoadICState::GetLanguageMode(target()->extra_ic_state())); IC::set_target(code); } diff --git a/src/ic/ic-state.h b/src/ic/ic-state.h index dbc504b..89e455d 100644 --- a/src/ic/ic-state.h +++ b/src/ic/ic-state.h @@ -201,11 +201,21 @@ class CompareICState { class LoadICState final BASE_EMBEDDED { + private: + class ContextualModeBits : public BitField {}; + class LanguageModeBits : public BitField {}; + STATIC_ASSERT(static_cast(NOT_CONTEXTUAL) == 0); + const ExtraICState state_; + public: + static const ExtraICState kStrongModeState = STRONG + << LanguageModeBits::kShift; + explicit LoadICState(ExtraICState extra_ic_state) : state_(extra_ic_state) {} - explicit LoadICState(ContextualMode mode) - : state_(ContextualModeBits::encode(mode)) {} + explicit LoadICState(ContextualMode mode, LanguageMode language_mode) + : state_(ContextualModeBits::encode(mode) | + LanguageModeBits::encode(language_mode)) {} ExtraICState GetExtraICState() const { return state_; } @@ -213,15 +223,17 @@ class LoadICState final BASE_EMBEDDED { return ContextualModeBits::decode(state_); } + LanguageMode language_mode() const { + return LanguageModeBits::decode(state_); + } + static ContextualMode GetContextualMode(ExtraICState state) { return LoadICState(state).contextual_mode(); } - private: - class ContextualModeBits : public BitField {}; - STATIC_ASSERT(static_cast(NOT_CONTEXTUAL) == 0); - - const ExtraICState state_; + static LanguageMode GetLanguageMode(ExtraICState state) { + return LoadICState(state).language_mode(); + } }; diff --git a/src/ic/ic.cc b/src/ic/ic.cc index 7c14b56..5499d80 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc @@ -571,11 +571,14 @@ void CompareIC::Clear(Isolate* isolate, Address address, Code* target, // static -Handle KeyedLoadIC::ChooseMegamorphicStub(Isolate* isolate) { +Handle KeyedLoadIC::ChooseMegamorphicStub(Isolate* isolate, + ExtraICState extra_state) { if (FLAG_compiled_keyed_generic_loads) { - return KeyedLoadGenericStub(isolate).GetCode(); + return KeyedLoadGenericStub(isolate, LoadICState(extra_state)).GetCode(); } else { - return isolate->builtins()->KeyedLoadIC_Megamorphic(); + return is_strong(LoadICState::GetLanguageMode(extra_state)) + ? isolate->builtins()->KeyedLoadIC_Megamorphic_Strong() + : isolate->builtins()->KeyedLoadIC_Megamorphic(); } } @@ -679,7 +682,8 @@ MaybeHandle LoadIC::Load(Handle object, Handle name) { Handle result; ASSIGN_RETURN_ON_EXCEPTION( isolate(), result, - Runtime::GetElementOrCharAt(isolate(), object, index), Object); + Runtime::GetElementOrCharAt(isolate(), object, index, language_mode()), + Object); return result; } @@ -722,8 +726,9 @@ MaybeHandle LoadIC::Load(Handle object, Handle name) { // Get the property. Handle result; - ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it), - Object); + + ASSIGN_RETURN_ON_EXCEPTION( + isolate(), result, Object::GetProperty(&it, language_mode()), Object); if (it.IsFound()) { return result; } else if (!IsUndeclaredGlobal(object)) { @@ -915,25 +920,20 @@ Handle LoadIC::initialize_stub_in_optimized_code( } -Handle KeyedLoadIC::initialize_stub(Isolate* isolate) { - return KeyedLoadICTrampolineStub(isolate).GetCode(); +Handle KeyedLoadIC::initialize_stub(Isolate* isolate, + ExtraICState extra_state) { + return KeyedLoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode(); } Handle KeyedLoadIC::initialize_stub_in_optimized_code( - Isolate* isolate, State initialization_state) { + Isolate* isolate, State initialization_state, ExtraICState extra_state) { if (initialization_state != MEGAMORPHIC) { - return KeyedLoadICStub(isolate).GetCode(); + return KeyedLoadICStub(isolate, LoadICState(extra_state)).GetCode(); } - switch (initialization_state) { - case UNINITIALIZED: - return isolate->builtins()->KeyedLoadIC_Initialize(); - case MEGAMORPHIC: - return isolate->builtins()->KeyedLoadIC_Megamorphic(); - default: - UNREACHABLE(); - } - return Handle(); + return is_strong(LoadICState::GetLanguageMode(extra_state)) + ? isolate->builtins()->KeyedLoadIC_Megamorphic_Strong() + : isolate->builtins()->KeyedLoadIC_Megamorphic(); } @@ -962,7 +962,7 @@ Handle KeyedStoreIC::initialize_stub(Isolate* isolate, Handle LoadIC::megamorphic_stub() { DCHECK_EQ(Code::KEYED_LOAD_IC, kind()); - return KeyedLoadIC::ChooseMegamorphicStub(isolate()); + return KeyedLoadIC::ChooseMegamorphicStub(isolate(), extra_ic_state()); } @@ -986,7 +986,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) { lookup->state() == LookupIterator::ACCESS_CHECK) { code = slow_stub(); } else if (!lookup->IsFound()) { - if (kind() == Code::LOAD_IC) { + if (kind() == Code::LOAD_IC && !is_strong(language_mode())) { code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(), receiver_map()); // TODO(jkummerow/verwaest): Introduce a builtin that handles this case. @@ -1245,7 +1245,8 @@ Handle KeyedLoadIC::LoadElementStub(Handle receiver) { if (target_receiver_maps.length() == 0) { Handle handler = - PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map); + PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( + receiver_map, extra_ic_state()); ConfigureVectorState(Handle::null(), receiver_map, handler); return null_handle; } @@ -1262,7 +1263,8 @@ Handle KeyedLoadIC::LoadElementStub(Handle receiver) { target_receiver_maps.at(0)->elements_kind(), Handle::cast(receiver)->GetElementsKind())) { Handle handler = - PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map); + PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( + receiver_map, extra_ic_state()); ConfigureVectorState(Handle::null(), receiver_map, handler); return null_handle; } @@ -1287,7 +1289,8 @@ Handle KeyedLoadIC::LoadElementStub(Handle receiver) { CodeHandleList handlers(target_receiver_maps.length()); ElementHandlerCompiler compiler(isolate()); - compiler.CompileElementHandlers(&target_receiver_maps, &handlers); + compiler.CompileElementHandlers(&target_receiver_maps, &handlers, + language_mode()); ConfigureVectorState(Handle::null(), &target_receiver_maps, &handlers); return null_handle; } @@ -1298,7 +1301,8 @@ MaybeHandle KeyedLoadIC::Load(Handle object, if (MigrateDeprecated(object)) { Handle result; ASSIGN_RETURN_ON_EXCEPTION( - isolate(), result, Runtime::GetObjectProperty(isolate(), object, key), + isolate(), result, + Runtime::GetObjectProperty(isolate(), object, key, language_mode()), Object); return result; } @@ -1346,10 +1350,12 @@ MaybeHandle KeyedLoadIC::Load(Handle object, } if (!load_handle.is_null()) return load_handle; + Handle result; - ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, - Runtime::GetObjectProperty(isolate(), object, key), - Object); + ASSIGN_RETURN_ON_EXCEPTION( + isolate(), result, + Runtime::GetObjectProperty(isolate(), object, key, language_mode()), + Object); return result; } @@ -2812,6 +2818,7 @@ RUNTIME_FUNCTION(LoadPropertyWithInterceptor) { Handle result; LookupIterator it(receiver, name, holder); + // TODO(conradw): Investigate strong mode semantics for this. ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::GetProperty(&it)); @@ -2857,8 +2864,11 @@ RUNTIME_FUNCTION(LoadElementWithInterceptor) { DCHECK(args.smi_at(1) >= 0); uint32_t index = args.smi_at(1); Handle result; + // TODO(conradw): Investigate strong mode semantics for this. + LanguageMode language_mode = SLOPPY; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, Object::GetElement(isolate, receiver, index)); + isolate, result, + Object::GetElement(isolate, receiver, index, language_mode)); return *result; } @@ -2894,6 +2904,36 @@ RUNTIME_FUNCTION(LoadIC_MissFromStubFailure) { } +RUNTIME_FUNCTION(LoadIC_Slow) { + HandleScope scope(isolate); + DCHECK(args.length() == 2); + + Handle receiver = args.at(0); + Handle name = args.at(1); + LoadIC ic(IC::NO_EXTRA_FRAME, isolate, true); + Handle result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + Runtime::GetObjectProperty(isolate, receiver, name, ic.language_mode())); + return *result; +} + + +RUNTIME_FUNCTION(KeyedLoadIC_Slow) { + HandleScope scope(isolate); + DCHECK(args.length() == 2); + + Handle receiver = args.at(0); + Handle key = args.at(1); + LoadIC ic(IC::NO_EXTRA_FRAME, isolate, true); + Handle result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, Runtime::KeyedGetObjectProperty(isolate, receiver, key, + ic.language_mode())); + return *result; +} + + static const Address IC_utilities[] = { #define ADDR(name) FUNCTION_ADDR(name), IC_UTIL_LIST(ADDR) NULL @@ -2902,5 +2942,5 @@ static const Address IC_utilities[] = { Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; } -} // namespace internal -} // namespace v8 +} +} // namespace v8::internal diff --git a/src/ic/ic.h b/src/ic/ic.h index c346306..935d856 100644 --- a/src/ic/ic.h +++ b/src/ic/ic.h @@ -18,6 +18,8 @@ namespace internal { #define IC_UTIL_LIST(ICU) \ ICU(LoadIC_Miss) \ ICU(KeyedLoadIC_Miss) \ + ICU(LoadIC_Slow) \ + ICU(KeyedLoadIC_Slow) \ ICU(CallIC_Miss) \ ICU(CallIC_Customization_Miss) \ ICU(StoreIC_Miss) \ @@ -352,14 +354,19 @@ class CallIC : public IC { class LoadIC : public IC { public: - static ExtraICState ComputeExtraICState(ContextualMode contextual_mode) { - return LoadICState(contextual_mode).GetExtraICState(); + static ExtraICState ComputeExtraICState(ContextualMode contextual_mode, + LanguageMode language_mode) { + return LoadICState(contextual_mode, language_mode).GetExtraICState(); } ContextualMode contextual_mode() const { return LoadICState::GetContextualMode(extra_ic_state()); } + LanguageMode language_mode() const { + return LoadICState::GetLanguageMode(extra_ic_state()); + } + LoadIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL) : IC(depth, isolate, nexus) { DCHECK(nexus != NULL); @@ -390,7 +397,7 @@ class LoadIC : public IC { static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } static void GenerateMiss(MacroAssembler* masm); static void GenerateNormal(MacroAssembler* masm); - static void GenerateRuntimeGetProperty(MacroAssembler* masm); + static void GenerateSlow(MacroAssembler* masm); static Handle initialize_stub(Isolate* isolate, ExtraICState extra_state); @@ -437,11 +444,12 @@ class LoadIC : public IC { class KeyedLoadIC : public LoadIC { public: // ExtraICState bits (building on IC) - class IcCheckTypeField : public BitField {}; + class IcCheckTypeField : public BitField {}; static ExtraICState ComputeExtraICState(ContextualMode contextual_mode, + LanguageMode language_mode, IcCheckType key_type) { - return LoadICState(contextual_mode).GetExtraICState() | + return LoadICState(contextual_mode, language_mode).GetExtraICState() | IcCheckTypeField::encode(key_type); } @@ -461,9 +469,10 @@ class KeyedLoadIC : public LoadIC { // Code generator routines. static void GenerateMiss(MacroAssembler* masm); - static void GenerateRuntimeGetProperty(MacroAssembler* masm); + static void GenerateSlow(MacroAssembler* masm); static void GenerateInitialize(MacroAssembler* masm) { GenerateMiss(masm); } - static void GenerateMegamorphic(MacroAssembler* masm); + static void GenerateMegamorphic(MacroAssembler* masm, + LanguageMode languageMode); // Bit mask to be tested against bit field for the cases when // generic stub should go into slow case. @@ -472,10 +481,12 @@ class KeyedLoadIC : public LoadIC { static const int kSlowCaseBitFieldMask = (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor); - static Handle initialize_stub(Isolate* isolate); + static Handle initialize_stub(Isolate* isolate, + ExtraICState extra_state); static Handle initialize_stub_in_optimized_code( - Isolate* isolate, State initialization_state); - static Handle ChooseMegamorphicStub(Isolate* isolate); + Isolate* isolate, State initialization_state, ExtraICState extra_state); + static Handle ChooseMegamorphicStub(Isolate* isolate, + ExtraICState extra_state); static void Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus); diff --git a/src/ic/mips/handler-compiler-mips.cc b/src/ic/mips/handler-compiler-mips.cc index 13ce921..34c11b1 100644 --- a/src/ic/mips/handler-compiler-mips.cc +++ b/src/ic/mips/handler-compiler-mips.cc @@ -16,6 +16,30 @@ namespace internal { #define __ ACCESS_MASM(masm) +void NamedLoadHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Push receiver and key for runtime call. + __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + +void ElementHandlerCompiler::GenerateLoadSlow(MacroAssembler* masm) { + // Push receiver and key for runtime call. + __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kKeyedLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + void NamedLoadHandlerCompiler::GenerateLoadViaGetter( MacroAssembler* masm, Handle map, Register receiver, Register holder, int accessor_index, int expected_arguments, Register scratch) { diff --git a/src/ic/mips/ic-mips.cc b/src/ic/mips/ic-mips.cc index 7dbaad7..0170959 100644 --- a/src/ic/mips/ic-mips.cc +++ b/src/ic/mips/ic-mips.cc @@ -163,7 +163,8 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, Register key, Register elements, Register scratch1, Register scratch2, - Register result, Label* slow) { + Register result, Label* slow, + LanguageMode language_mode) { // Register use: // // receiver - holds the receiver on entry. @@ -185,7 +186,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, // // scratch2 - used to hold maps, prototypes, and the loaded value. Label check_prototypes, check_next_prototype; - Label done, in_bounds, return_undefined; + Label done, in_bounds, absent; __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); __ AssertFastElements(elements); @@ -203,7 +204,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ lw(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset)); // scratch2: current prototype __ LoadRoot(at, Heap::kNullValueRootIndex); - __ Branch(&return_undefined, eq, scratch2, Operand(at)); + __ Branch(&absent, eq, scratch2, Operand(at)); __ lw(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset)); __ lw(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset)); // elements: elements of current prototype @@ -218,9 +219,14 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ Branch(slow, ne, elements, Operand(at)); __ Branch(&check_next_prototype); - __ bind(&return_undefined); - __ LoadRoot(result, Heap::kUndefinedValueRootIndex); - __ Branch(&done); + __ bind(&absent); + if (is_strong(language_mode)) { + // Strong mode accesses must throw in this case, so call the runtime. + __ Branch(slow); + } else { + __ LoadRoot(result, Heap::kUndefinedValueRootIndex); + __ Branch(&done); + } __ bind(&in_bounds); // Fast case: Do the load. @@ -285,7 +291,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { // Dictionary load failed, go slow (but don't miss). __ bind(&slow); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); } @@ -320,13 +326,16 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { } -void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void LoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is in ra. __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister()); __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister()); - __ TailCallRuntime(Runtime::kGetProperty, 2, 1); + ExternalReference ref = + ExternalReference(IC_Utility(kLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } @@ -349,16 +358,20 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { } -void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void KeyedLoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is in ra. __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); - __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); + ExternalReference ref = + ExternalReference(IC_Utility(kKeyedLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } -void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { +void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm, + LanguageMode language_mode) { // The return address is in ra. Label slow, check_name, index_smi, index_name, property_array_property; Label probe_dictionary, check_number_dictionary; @@ -382,7 +395,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { // Check the receiver's map to see if it has fast elements. __ CheckFastElements(a0, a3, &check_number_dictionary); - GenerateFastArrayLoad(masm, receiver, key, a0, a3, t0, v0, &slow); + GenerateFastArrayLoad(masm, receiver, key, a0, a3, t0, v0, &slow, + language_mode); __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, t0, a3); __ Ret(); @@ -403,7 +417,7 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { __ bind(&slow); __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1, t0, a3); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); __ bind(&check_name); GenerateKeyNameCheck(masm, key, a0, a3, &index_name, &slow); diff --git a/src/ic/mips64/handler-compiler-mips64.cc b/src/ic/mips64/handler-compiler-mips64.cc index d83c807..2a0ec06 100644 --- a/src/ic/mips64/handler-compiler-mips64.cc +++ b/src/ic/mips64/handler-compiler-mips64.cc @@ -16,6 +16,30 @@ namespace internal { #define __ ACCESS_MASM(masm) +void NamedLoadHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Push receiver and key for runtime call. + __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + +void ElementHandlerCompiler::GenerateLoadSlow(MacroAssembler* masm) { + // Push receiver and key for runtime call. + __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::kKeyedLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + void NamedLoadHandlerCompiler::GenerateLoadViaGetter( MacroAssembler* masm, Handle map, Register receiver, Register holder, int accessor_index, int expected_arguments, Register scratch) { diff --git a/src/ic/mips64/ic-mips64.cc b/src/ic/mips64/ic-mips64.cc index 770fa77..cbe9c0d 100644 --- a/src/ic/mips64/ic-mips64.cc +++ b/src/ic/mips64/ic-mips64.cc @@ -162,7 +162,8 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, Register key, Register elements, Register scratch1, Register scratch2, - Register result, Label* slow) { + Register result, Label* slow, + LanguageMode language_mode) { // Register use: // // receiver - holds the receiver on entry. @@ -184,7 +185,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, // // scratch2 - used to hold maps, prototypes, and the loaded value. Label check_prototypes, check_next_prototype; - Label done, in_bounds, return_undefined; + Label done, in_bounds, absent; __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); __ AssertFastElements(elements); @@ -202,7 +203,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ ld(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset)); // scratch2: current prototype __ LoadRoot(at, Heap::kNullValueRootIndex); - __ Branch(&return_undefined, eq, scratch2, Operand(at)); + __ Branch(&absent, eq, scratch2, Operand(at)); __ ld(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset)); __ ld(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset)); // elements: elements of current prototype @@ -217,9 +218,13 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ Branch(slow, ne, elements, Operand(at)); __ Branch(&check_next_prototype); - __ bind(&return_undefined); - __ LoadRoot(result, Heap::kUndefinedValueRootIndex); - __ Branch(&done); + __ bind(&absent); + if (is_strong(language_mode)) { + __ Branch(slow); + } else { + __ LoadRoot(result, Heap::kUndefinedValueRootIndex); + __ Branch(&done); + } __ bind(&in_bounds); // Fast case: Do the load. @@ -283,7 +288,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { // Dictionary load failed, go slow (but don't miss). __ bind(&slow); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); } @@ -318,7 +323,7 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { } -void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void LoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is in ra. __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister()); @@ -347,7 +352,7 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { } -void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void KeyedLoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is in ra. __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); @@ -356,7 +361,8 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { } -void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { +void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm, + LanguageMode language_mode) { // The return address is in ra. Label slow, check_name, index_smi, index_name, property_array_property; Label probe_dictionary, check_number_dictionary; @@ -380,7 +386,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { // Check the receiver's map to see if it has fast elements. __ CheckFastElements(a0, a3, &check_number_dictionary); - GenerateFastArrayLoad(masm, receiver, key, a0, a3, a4, v0, &slow); + GenerateFastArrayLoad(masm, receiver, key, a0, a3, a4, v0, &slow, + language_mode); __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a4, a3); __ Ret(); @@ -401,7 +408,7 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { __ bind(&slow); __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1, a4, a3); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); __ bind(&check_name); GenerateKeyNameCheck(masm, key, a0, a3, &index_name, &slow); diff --git a/src/ic/ppc/handler-compiler-ppc.cc b/src/ic/ppc/handler-compiler-ppc.cc index 8988b08..0a802f0 100644 --- a/src/ic/ppc/handler-compiler-ppc.cc +++ b/src/ic/ppc/handler-compiler-ppc.cc @@ -16,6 +16,30 @@ namespace internal { #define __ ACCESS_MASM(masm) +void NamedLoadHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Push receiver and key for runtime call. + __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::LoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + +void NamedLoadHandlerCompiler::GenerateLoadSlow(MacroAssembler* masm) { + // Push receiver and key for runtime call. + __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); + + // The slow case calls into the runtime to complete the store without causing + // an IC miss that would otherwise cause a transition to the generic stub. + ExternalReference ref = + ExternalReference(IC_Utility(IC::KeyedLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + void NamedLoadHandlerCompiler::GenerateLoadViaGetter( MacroAssembler* masm, Handle map, Register receiver, Register holder, int accessor_index, int expected_arguments, Register scratch) { diff --git a/src/ic/ppc/ic-ppc.cc b/src/ic/ppc/ic-ppc.cc index fdb88ae..6b4fc45 100644 --- a/src/ic/ppc/ic-ppc.cc +++ b/src/ic/ppc/ic-ppc.cc @@ -167,7 +167,8 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, Register key, Register elements, Register scratch1, Register scratch2, - Register result, Label* slow) { + Register result, Label* slow, + LanguageMode language_mode) { // Register use: // // receiver - holds the receiver on entry. @@ -189,7 +190,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, // // scratch2 - used to hold maps, prototypes, and the loaded value. Label check_prototypes, check_next_prototype; - Label done, in_bounds, return_undefined; + Label done, in_bounds, absent; __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); __ AssertFastElements(elements); @@ -208,7 +209,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ LoadP(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset)); // scratch2: current prototype __ CompareRoot(scratch2, Heap::kNullValueRootIndex); - __ beq(&return_undefined); + __ beq(&absent); __ LoadP(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset)); __ LoadP(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset)); // elements: elements of current prototype @@ -223,9 +224,14 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ bne(slow); __ jmp(&check_next_prototype); - __ bind(&return_undefined); - __ LoadRoot(result, Heap::kUndefinedValueRootIndex); - __ jmp(&done); + __ bind(&absent); + if (is_strong(language_mode)) { + // Strong mode accesses must throw in this case, so call the runtime. + __ jmp(slow); + } else { + __ LoadRoot(result, Heap::kUndefinedValueRootIndex); + __ jmp(&done); + } __ bind(&in_bounds); // Fast case: Do the load. @@ -288,7 +294,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { // Dictionary load failed, go slow (but don't miss). __ bind(&slow); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); } @@ -323,13 +329,16 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { } -void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void LoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is in lr. __ mr(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister()); __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister()); - __ TailCallRuntime(Runtime::kGetProperty, 2, 1); + ExternalReference ref = + ExternalReference(IC_Utility(kLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } @@ -351,16 +360,20 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { } -void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void KeyedLoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is in lr. __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); - __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); + ExternalReference ref = + ExternalReference(IC_Utility(kKeyedLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } -void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { +void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm, + LanguageMode language_mode) { // The return address is in lr. Label slow, check_name, index_smi, index_name, property_array_property; Label probe_dictionary, check_number_dictionary; @@ -384,7 +397,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { // Check the receiver's map to see if it has fast elements. __ CheckFastElements(r3, r6, &check_number_dictionary); - GenerateFastArrayLoad(masm, receiver, key, r3, r6, r7, r3, &slow); + GenerateFastArrayLoad(masm, receiver, key, r3, r6, r7, r3, &slow, + language_mode); __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r7, r6); __ Ret(); @@ -406,7 +420,7 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { __ bind(&slow); __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1, r7, r6); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); __ bind(&check_name); GenerateKeyNameCheck(masm, key, r3, r6, &index_name, &slow); diff --git a/src/ic/x64/handler-compiler-x64.cc b/src/ic/x64/handler-compiler-x64.cc index 43754c3..73fecca 100644 --- a/src/ic/x64/handler-compiler-x64.cc +++ b/src/ic/x64/handler-compiler-x64.cc @@ -261,6 +261,39 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter( } +static void LoadIC_PushArgs(MacroAssembler* masm) { + Register receiver = LoadDescriptor::ReceiverRegister(); + Register name = LoadDescriptor::NameRegister(); + + DCHECK(!rbx.is(receiver) && !rbx.is(name)); + + __ PopReturnAddressTo(rbx); + __ Push(receiver); + __ Push(name); + __ PushReturnAddressFrom(rbx); +} + + +void NamedLoadHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Return address is on the stack. + LoadIC_PushArgs(masm); + + // Do tail-call to runtime routine. + ExternalReference ref(IC_Utility(IC::kLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + +void ElementHandlerCompiler::GenerateLoadSlow(MacroAssembler* masm) { + // Return address is on the stack. + LoadIC_PushArgs(masm); + + // Do tail-call to runtime routine. + ExternalReference ref(IC_Utility(IC::kKeyedLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + void NamedLoadHandlerCompiler::GenerateLoadViaGetter( MacroAssembler* masm, Handle map, Register receiver, Register holder, int accessor_index, int expected_arguments, Register scratch) { diff --git a/src/ic/x64/ic-x64.cc b/src/ic/x64/ic-x64.cc index 40aa231..6d40a50 100644 --- a/src/ic/x64/ic-x64.cc +++ b/src/ic/x64/ic-x64.cc @@ -171,7 +171,7 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, Register key, Register elements, Register scratch, Register result, - Label* slow) { + Label* slow, LanguageMode language_mode) { // Register use: // // receiver - holds the receiver on entry. @@ -191,7 +191,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, // // scratch - used to hold maps, prototypes, and the loaded value. Label check_prototypes, check_next_prototype; - Label done, in_bounds, return_undefined; + Label done, in_bounds, absent; __ movp(elements, FieldOperand(receiver, JSObject::kElementsOffset)); __ AssertFastElements(elements); @@ -210,7 +210,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ movp(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); // scratch: current prototype __ CompareRoot(scratch, Heap::kNullValueRootIndex); - __ j(equal, &return_undefined); + __ j(equal, &absent); __ movp(elements, FieldOperand(scratch, JSObject::kElementsOffset)); __ movp(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); // elements: elements of current prototype @@ -225,9 +225,14 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ j(not_equal, slow); __ jmp(&check_next_prototype); - __ bind(&return_undefined); - __ LoadRoot(result, Heap::kUndefinedValueRootIndex); - __ jmp(&done); + __ bind(&absent); + if (is_strong(language_mode)) { + // Strong mode accesses must throw in this case, so call the runtime. + __ jmp(slow); + } else { + __ LoadRoot(result, Heap::kUndefinedValueRootIndex); + __ jmp(&done); + } __ bind(&in_bounds); // Fast case: Do the load. @@ -274,7 +279,8 @@ static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, } -void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { +void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm, + LanguageMode language_mode) { // The return address is on the stack. Label slow, check_name, index_smi, index_name, property_array_property; Label probe_dictionary, check_number_dictionary; @@ -296,7 +302,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { // Check the receiver's map to see if it has fast elements. __ CheckFastElements(rax, &check_number_dictionary); - GenerateFastArrayLoad(masm, receiver, key, rax, rbx, rax, &slow); + GenerateFastArrayLoad(masm, receiver, key, rax, rbx, rax, &slow, + language_mode); Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->keyed_load_generic_smi(), 1); __ ret(0); @@ -317,7 +324,7 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { __ bind(&slow); // Slow case: Jump to runtime. __ IncrementCounter(counters->keyed_load_generic_slow(), 1); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); __ bind(&check_name); GenerateKeyNameCheck(masm, key, rax, rbx, &index_name, &slow); @@ -623,7 +630,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { // Dictionary load failed, go slow (but don't miss). __ bind(&slow); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); } @@ -660,7 +667,7 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { } -void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void LoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is on the stack. Register receiver = LoadDescriptor::ReceiverRegister(); Register name = LoadDescriptor::NameRegister(); @@ -672,7 +679,10 @@ void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { __ PushReturnAddressFrom(rbx); // Perform tail call to the entry. - __ TailCallRuntime(Runtime::kGetProperty, 2, 1); + ExternalReference ref = + ExternalReference(IC_Utility(kLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } @@ -691,7 +701,7 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { } -void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void KeyedLoadIC::GenerateSlow(MacroAssembler* masm) { // The return address is on the stack. Register receiver = LoadDescriptor::ReceiverRegister(); Register name = LoadDescriptor::NameRegister(); @@ -703,7 +713,10 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { __ PushReturnAddressFrom(rbx); // Perform tail call to the entry. - __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); + ExternalReference ref = + ExternalReference(IC_Utility(kKeyedLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } diff --git a/src/ic/x87/handler-compiler-x87.cc b/src/ic/x87/handler-compiler-x87.cc index 056bd95..256c863 100644 --- a/src/ic/x87/handler-compiler-x87.cc +++ b/src/ic/x87/handler-compiler-x87.cc @@ -16,6 +16,39 @@ namespace internal { #define __ ACCESS_MASM(masm) +static void LoadIC_PushArgs(MacroAssembler* masm) { + Register receiver = LoadDescriptor::ReceiverRegister(); + Register name = LoadDescriptor::NameRegister(); + + DCHECK(!ebx.is(receiver) && !ebx.is(name)); + + __ pop(ebx); + __ push(receiver); + __ push(name); + __ push(ebx); +} + + +void NamedLoadHandlerCompiler::GenerateSlow(MacroAssembler* masm) { + // Return address is on the stack. + LoadIC_PushArgs(masm); + + // Do tail-call to runtime routine. + ExternalReference ref(IC_Utility(IC::kLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + +void ElementHandlerCompiler::GenerateLoadSlow(MacroAssembler* masm) { + // Return address is on the stack. + LoadIC_PushArgs(masm); + + // Do tail-call to runtime routine. + ExternalReference ref(IC_Utility(IC::kKeyedLoadIC_Slow), masm->isolate()); + __ TailCallExternalReference(ref, 2, 1); +} + + void NamedLoadHandlerCompiler::GenerateLoadViaGetter( MacroAssembler* masm, Handle map, Register receiver, Register holder, int accessor_index, int expected_arguments, Register scratch) { diff --git a/src/ic/x87/ic-x87.cc b/src/ic/x87/ic-x87.cc index ee236a6..daa2ac0 100644 --- a/src/ic/x87/ic-x87.cc +++ b/src/ic/x87/ic-x87.cc @@ -172,7 +172,7 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, Register key, Register scratch, Register scratch2, Register result, - Label* slow) { + Label* slow, LanguageMode language_mode) { // Register use: // receiver - holds the receiver and is unchanged. // key - holds the key and is unchanged (must be a smi). @@ -182,7 +182,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, // result - holds the result on exit if the load succeeds and // we fall through. Label check_prototypes, check_next_prototype; - Label done, in_bounds, return_undefined; + Label done, in_bounds, absent; __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset)); __ AssertFastElements(scratch); @@ -200,7 +200,7 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ mov(scratch2, FieldOperand(scratch2, Map::kPrototypeOffset)); // scratch2: current prototype __ cmp(scratch2, masm->isolate()->factory()->null_value()); - __ j(equal, &return_undefined); + __ j(equal, &absent); __ mov(scratch, FieldOperand(scratch2, JSObject::kElementsOffset)); __ mov(scratch2, FieldOperand(scratch2, HeapObject::kMapOffset)); // scratch: elements of current prototype @@ -215,9 +215,14 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, __ j(not_equal, slow); __ jmp(&check_next_prototype); - __ bind(&return_undefined); - __ mov(result, masm->isolate()->factory()->undefined_value()); - __ jmp(&done); + __ bind(&absent); + if (is_strong(language_mode)) { + // Strong mode accesses must throw in this case, so call the runtime. + __jmp(slow); + } else { + __ mov(result, masm->isolate()->factory()->undefined_value()); + __ jmp(&done); + } __ bind(&in_bounds); // Fast case: Do the load. @@ -263,7 +268,8 @@ static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, } -void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { +void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm, + LanguageMode language_mode) { // The return address is on the stack. Label slow, check_name, index_smi, index_name, property_array_property; Label probe_dictionary, check_number_dictionary; @@ -285,7 +291,8 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { // Check the receiver's map to see if it has fast elements. __ CheckFastElements(eax, &check_number_dictionary); - GenerateFastArrayLoad(masm, receiver, key, eax, ebx, eax, &slow); + GenerateFastArrayLoad(masm, receiver, key, eax, ebx, eax, &slow, + language_mode); Isolate* isolate = masm->isolate(); Counters* counters = isolate->counters(); __ IncrementCounter(counters->keyed_load_generic_smi(), 1); @@ -317,7 +324,7 @@ void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { __ bind(&slow); // Slow case: jump to runtime. __ IncrementCounter(counters->keyed_load_generic_slow(), 1); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); __ bind(&check_name); GenerateKeyNameCheck(masm, key, eax, ebx, &index_name, &slow); @@ -623,7 +630,7 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { // Dictionary load failed, go slow (but don't miss). __ bind(&slow); - GenerateRuntimeGetProperty(masm); + GenerateSlow(masm); } @@ -658,7 +665,7 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { } -void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void LoadIC::GenerateSlow(MacroAssembler* masm) { // Return address is on the stack. Register receiver = LoadDescriptor::ReceiverRegister(); Register name = LoadDescriptor::NameRegister(); @@ -670,7 +677,10 @@ void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { __ push(ebx); // Perform tail call to the entry. - __ TailCallRuntime(Runtime::kGetProperty, 2, 1); + ExternalReference ref = + ExternalReference(IC_Utility(kLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } @@ -688,7 +698,7 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { } -void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { +void KeyedLoadIC::GenerateSlow(MacroAssembler* masm) { // Return address is on the stack. Register receiver = LoadDescriptor::ReceiverRegister(); Register name = LoadDescriptor::NameRegister(); @@ -700,7 +710,10 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { __ push(ebx); // Perform tail call to the entry. - __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); + ExternalReference ref = + ExternalReference(IC_Utility(kKeyedLoadIC_Slow), masm->isolate()); + int arg_count = 2; + __ TailCallExternalReference(ref, arg_count, 1); } diff --git a/src/messages.h b/src/messages.h index 1862ff1..98eaf48 100644 --- a/src/messages.h +++ b/src/messages.h @@ -373,6 +373,8 @@ class CallSite { "instead") \ T(StrongForIn, \ "In strong mode, 'for'-'in' loops are deprecated, use 'for'-'of' instead") \ + T(StrongPropertyAccess, \ + "In strong mode, accessing missing property '%' of % is deprecated") \ T(StrongSuperCallDuplicate, \ "In strong mode, invoking the super constructor multiple times is " \ "deprecated") \ diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index 1b84534..aefc448 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -4592,7 +4592,7 @@ void LoadICTrampolineStub::Generate(MacroAssembler* masm) { void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { EmitLoadTypeFeedbackVector(masm, LoadWithVectorDescriptor::VectorRegister()); - KeyedLoadICStub stub(isolate()); + KeyedLoadICStub stub(isolate(), state()); stub.GenerateForTrampoline(masm); } @@ -4805,7 +4805,7 @@ void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex); __ Branch(&try_poly_name, ne, at, Operand(feedback)); Handle megamorphic_stub = - KeyedLoadIC::ChooseMegamorphicStub(masm->isolate()); + KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET); __ bind(&try_poly_name); diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index a44e02d..79d38b8 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -2229,7 +2229,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ lw(load_name, MemOperand(sp, 2 * kPointerSize)); __ li(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(expr->KeyedLoadFeedbackSlot()))); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code(); CallIC(ic, TypeFeedbackId::None()); __ mov(a0, v0); __ mov(a1, a0); @@ -2400,7 +2400,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { __ li(LoadDescriptor::NameRegister(), Operand(key->value())); __ li(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(prop->PropertyFeedbackSlot()))); - CallLoadIC(NOT_CONTEXTUAL); + CallLoadIC(NOT_CONTEXTUAL, language_mode()); } @@ -2412,13 +2412,14 @@ void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { DCHECK(prop->IsSuperAccess()); __ Push(key->value()); - __ CallRuntime(Runtime::kLoadFromSuper, 3); + __ Push(Smi::FromInt(language_mode())); + __ CallRuntime(Runtime::kLoadFromSuper, 4); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code(); __ li(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(prop->PropertyFeedbackSlot()))); CallIC(ic); @@ -2427,9 +2428,10 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { // Stack: receiver, home_object, key. + __ Push(Smi::FromInt(language_mode())); SetSourcePosition(prop->position()); - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); } @@ -2975,6 +2977,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { VisitForAccumulatorValue(super_ref->this_var()); __ Push(scratch, v0, v0, scratch); __ Push(key->value()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -2982,7 +2985,8 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadFromSuper, 4); // Replace home_object with target function. __ sw(v0, MemOperand(sp, kPointerSize)); @@ -3033,6 +3037,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { VisitForAccumulatorValue(super_ref->this_var()); __ Push(scratch, v0, v0, scratch); VisitForStackValue(prop->key()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -3040,7 +3045,8 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); // Replace home_object with target function. __ sw(v0, MemOperand(sp, kPointerSize)); diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index ccf0e53..2180215 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -2866,7 +2866,7 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { __ li(LoadDescriptor::NameRegister(), Operand(instr->name())); EmitVectorLoadICRegisters(instr); ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; - Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, + Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, SLOPPY, PREMONOMORPHIC).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -2966,9 +2966,10 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { // Name is always in a2. __ li(LoadDescriptor::NameRegister(), Operand(instr->name())); EmitVectorLoadICRegisters(instr); - Handle ic = CodeFactory::LoadICInOptimizedCode( - isolate(), NOT_CONTEXTUAL, - instr->hydrogen()->initialization_state()).code(); + Handle ic = + CodeFactory::LoadICInOptimizedCode( + isolate(), NOT_CONTEXTUAL, instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3293,9 +3294,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { EmitVectorLoadICRegisters(instr); } - Handle ic = - CodeFactory::KeyedLoadICInOptimizedCode( - isolate(), instr->hydrogen()->initialization_state()).code(); + Handle ic = CodeFactory::KeyedLoadICInOptimizedCode( + isolate(), instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/src/mips64/code-stubs-mips64.cc b/src/mips64/code-stubs-mips64.cc index 8c539b4..3baf78e 100644 --- a/src/mips64/code-stubs-mips64.cc +++ b/src/mips64/code-stubs-mips64.cc @@ -4636,7 +4636,7 @@ void LoadICTrampolineStub::Generate(MacroAssembler* masm) { void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { EmitLoadTypeFeedbackVector(masm, LoadWithVectorDescriptor::VectorRegister()); - KeyedLoadICStub stub(isolate()); + KeyedLoadICStub stub(isolate(), state()); stub.GenerateForTrampoline(masm); } @@ -4847,7 +4847,7 @@ void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex); __ Branch(&try_poly_name, ne, feedback, Operand(at)); Handle megamorphic_stub = - KeyedLoadIC::ChooseMegamorphicStub(masm->isolate()); + KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET); __ bind(&try_poly_name); diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc index 39abc3f..6c06cf7 100644 --- a/src/mips64/full-codegen-mips64.cc +++ b/src/mips64/full-codegen-mips64.cc @@ -2226,7 +2226,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ ld(load_name, MemOperand(sp, 2 * kPointerSize)); __ li(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(expr->KeyedLoadFeedbackSlot()))); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code(); CallIC(ic, TypeFeedbackId::None()); __ mov(a0, v0); __ mov(a1, a0); @@ -2399,7 +2399,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { __ li(LoadDescriptor::NameRegister(), Operand(key->value())); __ li(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(prop->PropertyFeedbackSlot()))); - CallLoadIC(NOT_CONTEXTUAL); + CallLoadIC(NOT_CONTEXTUAL, language_mode()); } @@ -2411,14 +2411,15 @@ void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { DCHECK(prop->IsSuperAccess()); __ Push(key->value()); - __ CallRuntime(Runtime::kLoadFromSuper, 3); + __ Push(Smi::FromInt(language_mode())); + __ CallRuntime(Runtime::kLoadFromSuper, 4); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); // Call keyed load IC. It has register arguments receiver and key. - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code(); __ li(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(prop->PropertyFeedbackSlot()))); CallIC(ic); @@ -2427,9 +2428,10 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { // Stack: receiver, home_object, key. + __ Push(Smi::FromInt(language_mode())); SetSourcePosition(prop->position()); - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); } @@ -2978,6 +2980,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { VisitForAccumulatorValue(super_ref->this_var()); __ Push(scratch, v0, v0, scratch); __ Push(key->value()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -2985,7 +2988,8 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadFromSuper, 4); // Replace home_object with target function. __ sd(v0, MemOperand(sp, kPointerSize)); @@ -3036,6 +3040,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { VisitForAccumulatorValue(super_ref->this_var()); __ Push(scratch, v0, v0, scratch); VisitForStackValue(prop->key()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -3043,7 +3048,8 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); // Replace home_object with target function. __ sd(v0, MemOperand(sp, kPointerSize)); diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc index 0082a3f..8b5dca3 100644 --- a/src/mips64/lithium-codegen-mips64.cc +++ b/src/mips64/lithium-codegen-mips64.cc @@ -2970,7 +2970,7 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { __ li(LoadDescriptor::NameRegister(), Operand(instr->name())); EmitVectorLoadICRegisters(instr); ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; - Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, + Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, SLOPPY, PREMONOMORPHIC).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3085,9 +3085,10 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { // Name is always in a2. __ li(LoadDescriptor::NameRegister(), Operand(instr->name())); EmitVectorLoadICRegisters(instr); - Handle ic = CodeFactory::LoadICInOptimizedCode( - isolate(), NOT_CONTEXTUAL, - instr->hydrogen()->initialization_state()).code(); + Handle ic = + CodeFactory::LoadICInOptimizedCode( + isolate(), NOT_CONTEXTUAL, instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3454,9 +3455,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { EmitVectorLoadICRegisters(instr); } - Handle ic = - CodeFactory::KeyedLoadICInOptimizedCode( - isolate(), instr->hydrogen()->initialization_state()).code(); + Handle ic = CodeFactory::KeyedLoadICInOptimizedCode( + isolate(), instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/src/objects-inl.h b/src/objects-inl.h index f218e48..af019fa 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -1162,17 +1162,18 @@ bool Object::HasSpecificClassOf(String* name) { MaybeHandle Object::GetProperty(Handle object, - Handle name) { + Handle name, + LanguageMode language_mode) { LookupIterator it(object, name); - return GetProperty(&it); + return GetProperty(&it, language_mode); } -MaybeHandle Object::GetElement(Isolate* isolate, - Handle object, - uint32_t index) { +MaybeHandle Object::GetElement(Isolate* isolate, Handle object, + uint32_t index, + LanguageMode language_mode) { LookupIterator it(isolate, object, index); - return GetProperty(&it); + return GetProperty(&it, language_mode); } @@ -1189,11 +1190,11 @@ Handle Object::GetPrototypeSkipHiddenPrototypes( } -MaybeHandle Object::GetProperty(Isolate* isolate, - Handle object, - const char* name) { +MaybeHandle Object::GetProperty(Isolate* isolate, Handle object, + const char* name, + LanguageMode language_mode) { Handle str = isolate->factory()->InternalizeUtf8String(name); - return GetProperty(object, str); + return GetProperty(object, str, language_mode); } @@ -6558,10 +6559,11 @@ String* String::GetForwardedInternalizedString() { MaybeHandle Object::GetPropertyOrElement(Handle object, - Handle name) { + Handle name, + LanguageMode language_mode) { LookupIterator it = LookupIterator::PropertyOrElement(name->GetIsolate(), object, name); - return GetProperty(&it); + return GetProperty(&it, language_mode); } diff --git a/src/objects.cc b/src/objects.cc index 0080588..ddd124d 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -127,7 +127,8 @@ bool Object::IsPromise(Handle object) { } -MaybeHandle Object::GetProperty(LookupIterator* it) { +MaybeHandle Object::GetProperty(LookupIterator* it, + LanguageMode language_mode) { for (; it->IsFound(); it->Next()) { switch (it->state()) { case LookupIterator::NOT_FOUND: @@ -147,16 +148,16 @@ MaybeHandle Object::GetProperty(LookupIterator* it) { } case LookupIterator::ACCESS_CHECK: if (it->HasAccess()) break; - return JSObject::GetPropertyWithFailedAccessCheck(it); + return JSObject::GetPropertyWithFailedAccessCheck(it, language_mode); case LookupIterator::ACCESSOR: - return GetPropertyWithAccessor(it); + return GetPropertyWithAccessor(it, language_mode); case LookupIterator::INTEGER_INDEXED_EXOTIC: - return it->factory()->undefined_value(); + return ReadAbsentProperty(it, language_mode); case LookupIterator::DATA: return it->GetDataValue(); } } - return it->factory()->undefined_value(); + return ReadAbsentProperty(it, language_mode); } @@ -304,7 +305,8 @@ MaybeHandle JSProxy::GetPropertyWithHandler(Handle proxy, } -MaybeHandle Object::GetPropertyWithAccessor(LookupIterator* it) { +MaybeHandle Object::GetPropertyWithAccessor( + LookupIterator* it, LanguageMode language_mode) { Isolate* isolate = it->isolate(); Handle structure = it->GetAccessors(); Handle receiver = it->GetReceiver(); @@ -336,7 +338,7 @@ MaybeHandle Object::GetPropertyWithAccessor(LookupIterator* it) { args.Call(call_fun, v8::Utils::ToLocal(name)); RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); if (result.IsEmpty()) { - return isolate->factory()->undefined_value(); + return ReadAbsentProperty(isolate, receiver, name, language_mode); } Handle return_value = v8::Utils::OpenHandle(*result); return_value->VerifyApiCallResultType(); @@ -352,7 +354,7 @@ MaybeHandle Object::GetPropertyWithAccessor(LookupIterator* it) { receiver, Handle::cast(getter)); } // Getter is not a function. - return isolate->factory()->undefined_value(); + return ReadAbsentProperty(isolate, receiver, it->GetName(), language_mode); } @@ -488,11 +490,11 @@ static bool FindAllCanReadHolder(LookupIterator* it) { MaybeHandle JSObject::GetPropertyWithFailedAccessCheck( - LookupIterator* it) { + LookupIterator* it, LanguageMode language_mode) { Handle checked = it->GetHolder(); while (FindAllCanReadHolder(it)) { if (it->state() == LookupIterator::ACCESSOR) { - return GetPropertyWithAccessor(it); + return GetPropertyWithAccessor(it, language_mode); } DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); bool done; @@ -3222,6 +3224,26 @@ MaybeHandle Object::SetSuperProperty(LookupIterator* it, } +MaybeHandle Object::ReadAbsentProperty(LookupIterator* it, + LanguageMode language_mode) { + return ReadAbsentProperty(it->isolate(), it->GetReceiver(), it->GetName(), + language_mode); +} + +MaybeHandle Object::ReadAbsentProperty(Isolate* isolate, + Handle receiver, + Handle name, + LanguageMode language_mode) { + if (is_strong(language_mode)) { + THROW_NEW_ERROR( + isolate, + NewTypeError(MessageTemplate::kStrongPropertyAccess, name, receiver), + Object); + } + return isolate->factory()->undefined_value(); +} + + MaybeHandle Object::WriteToReadOnlyProperty( LookupIterator* it, Handle value, LanguageMode language_mode) { return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), diff --git a/src/objects.h b/src/objects.h index f5ce1d6..05a301a 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1155,7 +1155,8 @@ class Object { MUST_USE_RESULT static inline MaybeHandle ToSmi(Isolate* isolate, Handle object); - MUST_USE_RESULT static MaybeHandle GetProperty(LookupIterator* it); + MUST_USE_RESULT static MaybeHandle GetProperty( + LookupIterator* it, LanguageMode language_mode = SLOPPY); // Implementation of [[Put]], ECMA-262 5th edition, section 8.12.5. MUST_USE_RESULT static MaybeHandle SetProperty( @@ -1171,10 +1172,15 @@ class Object { LookupIterator* it, Handle value, LanguageMode language_mode, StoreFromKeyed store_mode); + MUST_USE_RESULT static MaybeHandle ReadAbsentProperty( + LookupIterator* it, LanguageMode language_mode); + MUST_USE_RESULT static MaybeHandle ReadAbsentProperty( + Isolate* isolate, Handle receiver, Handle name, + LanguageMode language_mode); MUST_USE_RESULT static MaybeHandle WriteToReadOnlyProperty( LookupIterator* it, Handle value, LanguageMode language_mode); MUST_USE_RESULT static MaybeHandle WriteToReadOnlyProperty( - Isolate* isolate, Handle reciever, Handle name, + Isolate* isolate, Handle receiver, Handle name, Handle value, LanguageMode language_mode); MUST_USE_RESULT static MaybeHandle RedefineNonconfigurableProperty( Isolate* isolate, Handle name, Handle value, @@ -1185,16 +1191,17 @@ class Object { LookupIterator* it, Handle value, PropertyAttributes attributes, LanguageMode language_mode, StoreFromKeyed store_mode); MUST_USE_RESULT static inline MaybeHandle GetPropertyOrElement( - Handle object, Handle name); + Handle object, Handle name, + LanguageMode language_mode = SLOPPY); MUST_USE_RESULT static inline MaybeHandle GetProperty( - Isolate* isolate, - Handle object, - const char* key); + Isolate* isolate, Handle object, const char* key, + LanguageMode language_mode = SLOPPY); MUST_USE_RESULT static inline MaybeHandle GetProperty( - Handle object, Handle name); + Handle object, Handle name, + LanguageMode language_mode = SLOPPY); MUST_USE_RESULT static MaybeHandle GetPropertyWithAccessor( - LookupIterator* it); + LookupIterator* it, LanguageMode language_mode); MUST_USE_RESULT static MaybeHandle SetPropertyWithAccessor( LookupIterator* it, Handle value, LanguageMode language_mode); @@ -1207,9 +1214,8 @@ class Object { Handle value); MUST_USE_RESULT static inline MaybeHandle GetElement( - Isolate* isolate, - Handle object, - uint32_t index); + Isolate* isolate, Handle object, uint32_t index, + LanguageMode language_mode = SLOPPY); static inline Handle GetPrototypeSkipHiddenPrototypes( Isolate* isolate, Handle receiver); @@ -2321,7 +2327,7 @@ class JSObject: public JSReceiver { // Used from Object::GetProperty(). MUST_USE_RESULT static MaybeHandle GetPropertyWithFailedAccessCheck( - LookupIterator* it); + LookupIterator* it, LanguageMode language_mode); MUST_USE_RESULT static MaybeHandle SetPropertyWithFailedAccessCheck( LookupIterator* it, Handle value); diff --git a/src/ppc/code-stubs-ppc.cc b/src/ppc/code-stubs-ppc.cc index 9cc2bed..66124fb 100644 --- a/src/ppc/code-stubs-ppc.cc +++ b/src/ppc/code-stubs-ppc.cc @@ -4612,7 +4612,7 @@ void LoadICTrampolineStub::Generate(MacroAssembler* masm) { void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { EmitLoadTypeFeedbackVector(masm, LoadWithVectorDescriptor::VectorRegister()); - KeyedLoadICStub stub(isolate()); + KeyedLoadICStub stub(isolate(), state()); stub.GenerateForTrampoline(masm); } @@ -4829,7 +4829,7 @@ void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); __ bne(&try_poly_name); Handle megamorphic_stub = - KeyedLoadIC::ChooseMegamorphicStub(masm->isolate()); + KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET); __ bind(&try_poly_name); diff --git a/src/ppc/full-codegen-ppc.cc b/src/ppc/full-codegen-ppc.cc index 2e34d16..bac4496 100644 --- a/src/ppc/full-codegen-ppc.cc +++ b/src/ppc/full-codegen-ppc.cc @@ -2200,7 +2200,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ LoadP(load_name, MemOperand(sp, 2 * kPointerSize)); __ mov(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(expr->KeyedLoadFeedbackSlot()))); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code(); CallIC(ic, TypeFeedbackId::None()); __ mr(r4, r3); __ StoreP(r4, MemOperand(sp, 2 * kPointerSize)); @@ -2389,7 +2389,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { __ mov(LoadDescriptor::NameRegister(), Operand(key->value())); __ mov(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(prop->PropertyFeedbackSlot()))); - CallLoadIC(NOT_CONTEXTUAL); + CallLoadIC(NOT_CONTEXTUAL, language_mode()); } @@ -2401,13 +2401,14 @@ void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { DCHECK(prop->IsSuperAccess()); __ Push(key->value()); - __ CallRuntime(Runtime::kLoadFromSuper, 3); + __ Push(Smi::FromInt(language_mode())); + __ CallRuntime(Runtime::kLoadFromSuper, 4); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code(); __ mov(LoadDescriptor::SlotRegister(), Operand(SmiFromSlot(prop->PropertyFeedbackSlot()))); CallIC(ic); @@ -2416,9 +2417,10 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { // Stack: receiver, home_object, key. + __ Push(Smi::FromInt(language_mode())); SetSourcePosition(prop->position()); - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); } @@ -2990,6 +2992,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { VisitForAccumulatorValue(super_ref->this_var()); __ Push(scratch, r3, r3, scratch); __ Push(key->value()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -2997,7 +3000,8 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadFromSuper, 4); // Replace home_object with target function. __ StoreP(r3, MemOperand(sp, kPointerSize)); @@ -3047,6 +3051,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { VisitForAccumulatorValue(super_ref->this_var()); __ Push(scratch, r3, r3, scratch); VisitForStackValue(prop->key()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -3054,7 +3059,8 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); // Replace home_object with target function. __ StoreP(r3, MemOperand(sp, kPointerSize)); diff --git a/src/ppc/lithium-codegen-ppc.cc b/src/ppc/lithium-codegen-ppc.cc index fea04e3..cc2bb5a 100644 --- a/src/ppc/lithium-codegen-ppc.cc +++ b/src/ppc/lithium-codegen-ppc.cc @@ -3025,7 +3025,7 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { __ mov(LoadDescriptor::NameRegister(), Operand(instr->name())); EmitVectorLoadICRegisters(instr); ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; - Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, + Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, SLOPPY, PREMONOMORPHIC).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3141,9 +3141,10 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { // Name is always in r5. __ mov(LoadDescriptor::NameRegister(), Operand(instr->name())); EmitVectorLoadICRegisters(instr); - Handle ic = CodeFactory::LoadICInOptimizedCode( - isolate(), NOT_CONTEXTUAL, - instr->hydrogen()->initialization_state()).code(); + Handle ic = + CodeFactory::LoadICInOptimizedCode( + isolate(), NOT_CONTEXTUAL, instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3515,9 +3516,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { EmitVectorLoadICRegisters(instr); } - Handle ic = - CodeFactory::KeyedLoadICInOptimizedCode( - isolate(), instr->hydrogen()->initialization_state()).code(); + Handle ic = CodeFactory::KeyedLoadICInOptimizedCode( + isolate(), instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/src/runtime/runtime-classes.cc b/src/runtime/runtime-classes.cc index dedff92..95a65f5 100644 --- a/src/runtime/runtime-classes.cc +++ b/src/runtime/runtime-classes.cc @@ -120,7 +120,8 @@ RUNTIME_FUNCTION(Runtime_DefineClass) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, prototype_parent, Runtime::GetObjectProperty(isolate, super_class, - isolate->factory()->prototype_string())); + isolate->factory()->prototype_string(), + SLOPPY)); if (!prototype_parent->IsNull() && !prototype_parent->IsSpecObject()) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject, @@ -244,64 +245,87 @@ RUNTIME_FUNCTION(Runtime_ClassGetSourceCode) { } -static Object* LoadFromSuper(Isolate* isolate, Handle receiver, - Handle home_object, Handle name) { +static MaybeHandle LoadFromSuper(Isolate* isolate, + Handle receiver, + Handle home_object, + Handle name, + LanguageMode language_mode) { if (home_object->IsAccessCheckNeeded() && !isolate->MayAccess(home_object)) { isolate->ReportFailedAccessCheck(home_object); - RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); + RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); } PrototypeIterator iter(isolate, home_object); Handle proto = PrototypeIterator::GetCurrent(iter); - if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value(); + if (!proto->IsJSReceiver()) { + return Object::ReadAbsentProperty(isolate, proto, name, language_mode); + } LookupIterator it(receiver, name, Handle::cast(proto)); Handle result; - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it)); - return *result; + ASSIGN_RETURN_ON_EXCEPTION(isolate, result, + Object::GetProperty(&it, language_mode), Object); + return result; } -static Object* LoadElementFromSuper(Isolate* isolate, Handle receiver, - Handle home_object, - uint32_t index) { +static MaybeHandle LoadElementFromSuper(Isolate* isolate, + Handle receiver, + Handle home_object, + uint32_t index, + LanguageMode language_mode) { if (home_object->IsAccessCheckNeeded() && !isolate->MayAccess(home_object)) { isolate->ReportFailedAccessCheck(home_object); - RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); + RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); } PrototypeIterator iter(isolate, home_object); Handle proto = PrototypeIterator::GetCurrent(iter); - if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value(); + if (!proto->IsJSReceiver()) { + Handle name = isolate->factory()->NewNumberFromUint(index); + return Object::ReadAbsentProperty(isolate, proto, name, language_mode); + } LookupIterator it(isolate, receiver, index, Handle::cast(proto)); Handle result; - ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Object::GetProperty(&it)); - return *result; + ASSIGN_RETURN_ON_EXCEPTION(isolate, result, + Object::GetProperty(&it, language_mode), Object); + return result; } RUNTIME_FUNCTION(Runtime_LoadFromSuper) { HandleScope scope(isolate); - DCHECK(args.length() == 3); + DCHECK(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1); CONVERT_ARG_HANDLE_CHECKED(Name, name, 2); + CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3); - return LoadFromSuper(isolate, receiver, home_object, name); + Handle result; + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + LoadFromSuper(isolate, receiver, home_object, name, language_mode)); + return *result; } RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) { HandleScope scope(isolate); - DCHECK(args.length() == 3); + DCHECK(args.length() == 4); CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1); CONVERT_ARG_HANDLE_CHECKED(Object, key, 2); + CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3); uint32_t index = 0; + Handle result; + if (key->ToArrayIndex(&index)) { - return LoadElementFromSuper(isolate, receiver, home_object, index); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, LoadElementFromSuper(isolate, receiver, home_object, + index, language_mode)); + return *result; } Handle name; @@ -309,9 +333,15 @@ RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) { Runtime::ToName(isolate, key)); // TODO(verwaest): Unify using LookupIterator. if (name->AsArrayIndex(&index)) { - return LoadElementFromSuper(isolate, receiver, home_object, index); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, LoadElementFromSuper(isolate, receiver, home_object, + index, language_mode)); + return *result; } - return LoadFromSuper(isolate, receiver, home_object, name); + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( + isolate, result, + LoadFromSuper(isolate, receiver, home_object, name, language_mode)); + return *result; } diff --git a/src/runtime/runtime-debug.cc b/src/runtime/runtime-debug.cc index 5baa151..1c808a7 100644 --- a/src/runtime/runtime-debug.cc +++ b/src/runtime/runtime-debug.cc @@ -81,7 +81,7 @@ static Handle DebugGetProperty(LookupIterator* it, return it->isolate()->factory()->undefined_value(); } MaybeHandle maybe_result = - JSObject::GetPropertyWithAccessor(it); + JSObject::GetPropertyWithAccessor(it, SLOPPY); Handle result; if (!maybe_result.ToHandle(&result)) { result = handle(it->isolate()->pending_exception(), it->isolate()); diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc index b3b917b..d119867 100644 --- a/src/runtime/runtime-object.cc +++ b/src/runtime/runtime-object.cc @@ -26,7 +26,8 @@ static Handle GetCharAt(Handle string, uint32_t index) { MaybeHandle Runtime::GetElementOrCharAt(Isolate* isolate, Handle object, - uint32_t index) { + uint32_t index, + LanguageMode language_mode) { // Handle [] indexing on Strings if (object->IsString() && index < static_cast(String::cast(*object)->length())) { @@ -34,7 +35,7 @@ MaybeHandle Runtime::GetElementOrCharAt(Isolate* isolate, if (!result->IsUndefined()) return result; } - return Object::GetElement(isolate, object, index); + return Object::GetElement(isolate, object, index, language_mode); } @@ -52,7 +53,8 @@ MaybeHandle Runtime::ToName(Isolate* isolate, Handle key) { MaybeHandle Runtime::GetObjectProperty(Isolate* isolate, Handle object, - Handle key) { + Handle key, + LanguageMode language_mode) { if (object->IsUndefined() || object->IsNull()) { THROW_NEW_ERROR( isolate, @@ -63,7 +65,7 @@ MaybeHandle Runtime::GetObjectProperty(Isolate* isolate, // Check if the given key is an array index. uint32_t index = 0; if (key->ToArrayIndex(&index)) { - return GetElementOrCharAt(isolate, object, index); + return GetElementOrCharAt(isolate, object, index, language_mode); } // Convert the key to a name - possibly by calling back into JavaScript. @@ -77,8 +79,109 @@ MaybeHandle Runtime::GetObjectProperty(Isolate* isolate, if (name->AsArrayIndex(&index)) { return GetElementOrCharAt(isolate, object, index); } else { - return Object::GetProperty(object, name); + return Object::GetProperty(object, name, language_mode); + } +} + + +MUST_USE_RESULT static MaybeHandle TransitionElements( + Handle object, ElementsKind to_kind, Isolate* isolate) { + HandleScope scope(isolate); + if (!object->IsJSObject()) { + isolate->ThrowIllegalOperation(); + return MaybeHandle(); + } + ElementsKind from_kind = + Handle::cast(object)->map()->elements_kind(); + if (Map::IsValidElementsTransition(from_kind, to_kind)) { + JSObject::TransitionElementsKind(Handle::cast(object), to_kind); + return object; } + isolate->ThrowIllegalOperation(); + return MaybeHandle(); +} + + +MaybeHandle Runtime::KeyedGetObjectProperty( + Isolate* isolate, Handle receiver_obj, Handle key_obj, + LanguageMode language_mode) { + // Fast cases for getting named properties of the receiver JSObject + // itself. + // + // The global proxy objects has to be excluded since LookupOwn on + // the global proxy object can return a valid result even though the + // global proxy object never has properties. This is the case + // because the global proxy object forwards everything to its hidden + // prototype including own lookups. + // + // Additionally, we need to make sure that we do not cache results + // for objects that require access checks. + if (receiver_obj->IsJSObject()) { + if (!receiver_obj->IsJSGlobalProxy() && + !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { + DisallowHeapAllocation no_allocation; + Handle receiver = Handle::cast(receiver_obj); + Handle key = Handle::cast(key_obj); + if (receiver->IsGlobalObject()) { + // Attempt dictionary lookup. + GlobalDictionary* dictionary = receiver->global_dictionary(); + int entry = dictionary->FindEntry(key); + if (entry != GlobalDictionary::kNotFound) { + DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); + PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry)); + if (cell->property_details().type() == DATA) { + Object* value = cell->value(); + if (!value->IsTheHole()) return Handle(value, isolate); + // If value is the hole (meaning, absent) do the general lookup. + } + } + } else if (!receiver->HasFastProperties()) { + // Attempt dictionary lookup. + NameDictionary* dictionary = receiver->property_dictionary(); + int entry = dictionary->FindEntry(key); + if ((entry != NameDictionary::kNotFound) && + (dictionary->DetailsAt(entry).type() == DATA)) { + Object* value = dictionary->ValueAt(entry); + return Handle(value, isolate); + } + } + } else if (key_obj->IsSmi()) { + // JSObject without a name key. If the key is a Smi, check for a + // definite out-of-bounds access to elements, which is a strong indicator + // that subsequent accesses will also call the runtime. Proactively + // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of + // doubles for those future calls in the case that the elements would + // become FAST_DOUBLE_ELEMENTS. + Handle js_object = Handle::cast(receiver_obj); + ElementsKind elements_kind = js_object->GetElementsKind(); + if (IsFastDoubleElementsKind(elements_kind)) { + Handle key = Handle::cast(key_obj); + if (key->value() >= js_object->elements()->length()) { + if (IsFastHoleyElementsKind(elements_kind)) { + elements_kind = FAST_HOLEY_ELEMENTS; + } else { + elements_kind = FAST_ELEMENTS; + } + RETURN_ON_EXCEPTION( + isolate, TransitionElements(js_object, elements_kind, isolate), + Object); + } + } else { + DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || + !IsFastElementsKind(elements_kind)); + } + } + } else if (receiver_obj->IsString() && key_obj->IsSmi()) { + // Fast case for string indexing using [] with a smi index. + Handle str = Handle::cast(receiver_obj); + int index = Handle::cast(key_obj)->value(); + if (index >= 0 && index < str->length()) { + return GetCharAt(str, index); + } + } + + // Fall back to GetObjectProperty. + return GetObjectProperty(isolate, receiver_obj, key_obj, language_mode); } @@ -383,122 +486,32 @@ RUNTIME_FUNCTION(Runtime_ObjectSeal) { RUNTIME_FUNCTION(Runtime_GetProperty) { HandleScope scope(isolate); - DCHECK(args.length() == 2); + DCHECK(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); + CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); + Handle result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, Runtime::GetObjectProperty(isolate, object, key)); + isolate, result, + Runtime::GetObjectProperty(isolate, object, key, language_mode)); return *result; } -MUST_USE_RESULT static MaybeHandle TransitionElements( - Handle object, ElementsKind to_kind, Isolate* isolate) { - HandleScope scope(isolate); - if (!object->IsJSObject()) { - isolate->ThrowIllegalOperation(); - return MaybeHandle(); - } - ElementsKind from_kind = - Handle::cast(object)->map()->elements_kind(); - if (Map::IsValidElementsTransition(from_kind, to_kind)) { - JSObject::TransitionElementsKind(Handle::cast(object), to_kind); - return object; - } - isolate->ThrowIllegalOperation(); - return MaybeHandle(); -} - - -// KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric. RUNTIME_FUNCTION(Runtime_KeyedGetProperty) { HandleScope scope(isolate); - DCHECK(args.length() == 2); + DCHECK(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0); CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1); + CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2); - // Fast cases for getting named properties of the receiver JSObject - // itself. - // - // The global proxy objects has to be excluded since LookupOwn on - // the global proxy object can return a valid result even though the - // global proxy object never has properties. This is the case - // because the global proxy object forwards everything to its hidden - // prototype including own lookups. - // - // Additionally, we need to make sure that we do not cache results - // for objects that require access checks. - if (receiver_obj->IsJSObject()) { - if (!receiver_obj->IsJSGlobalProxy() && - !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) { - DisallowHeapAllocation no_allocation; - Handle receiver = Handle::cast(receiver_obj); - Handle key = Handle::cast(key_obj); - if (receiver->IsGlobalObject()) { - // Attempt dictionary lookup. - GlobalDictionary* dictionary = receiver->global_dictionary(); - int entry = dictionary->FindEntry(key); - if (entry != GlobalDictionary::kNotFound) { - DCHECK(dictionary->ValueAt(entry)->IsPropertyCell()); - PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry)); - if (cell->property_details().type() == DATA) { - Object* value = cell->value(); - if (!value->IsTheHole()) return value; - // If value is the hole (meaning, absent) do the general lookup. - } - } - } else if (!receiver->HasFastProperties()) { - // Attempt dictionary lookup. - NameDictionary* dictionary = receiver->property_dictionary(); - int entry = dictionary->FindEntry(key); - if ((entry != NameDictionary::kNotFound) && - (dictionary->DetailsAt(entry).type() == DATA)) { - Object* value = dictionary->ValueAt(entry); - return value; - } - } - } else if (key_obj->IsSmi()) { - // JSObject without a name key. If the key is a Smi, check for a - // definite out-of-bounds access to elements, which is a strong indicator - // that subsequent accesses will also call the runtime. Proactively - // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of - // doubles for those future calls in the case that the elements would - // become FAST_DOUBLE_ELEMENTS. - Handle js_object = Handle::cast(receiver_obj); - ElementsKind elements_kind = js_object->GetElementsKind(); - if (IsFastDoubleElementsKind(elements_kind)) { - Handle key = Handle::cast(key_obj); - if (key->value() >= js_object->elements()->length()) { - if (IsFastHoleyElementsKind(elements_kind)) { - elements_kind = FAST_HOLEY_ELEMENTS; - } else { - elements_kind = FAST_ELEMENTS; - } - RETURN_FAILURE_ON_EXCEPTION( - isolate, TransitionElements(js_object, elements_kind, isolate)); - } - } else { - DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || - !IsFastElementsKind(elements_kind)); - } - } - } else if (receiver_obj->IsString() && key_obj->IsSmi()) { - // Fast case for string indexing using [] with a smi index. - Handle str = Handle::cast(receiver_obj); - int index = args.smi_at(1); - if (index >= 0 && index < str->length()) { - return *GetCharAt(str, index); - } - } - - // Fall back to GetObjectProperty. Handle result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( - isolate, result, - Runtime::GetObjectProperty(isolate, receiver_obj, key_obj)); + isolate, result, Runtime::KeyedGetObjectProperty(isolate, receiver_obj, + key_obj, language_mode)); return *result; } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index b8918c4..cf0b882 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -78,8 +78,8 @@ namespace internal { F(DefineClass, 6, 1) \ F(DefineClassMethod, 3, 1) \ F(ClassGetSourceCode, 1, 1) \ - F(LoadFromSuper, 3, 1) \ - F(LoadKeyedFromSuper, 3, 1) \ + F(LoadFromSuper, 4, 1) \ + F(LoadKeyedFromSuper, 4, 1) \ F(StoreToSuper_Strict, 4, 1) \ F(StoreToSuper_Sloppy, 4, 1) \ F(StoreKeyedToSuper_Strict, 4, 1) \ @@ -431,8 +431,8 @@ namespace internal { F(OptimizeObjectForAddingMultipleProperties, 2, 1) \ F(ObjectFreeze, 1, 1) \ F(ObjectSeal, 1, 1) \ - F(GetProperty, 2, 1) \ - F(KeyedGetProperty, 2, 1) \ + F(GetProperty, 3, 1) \ + F(KeyedGetProperty, 3, 1) \ F(AddNamedProperty, 4, 1) \ F(SetProperty, 4, 1) \ F(AddElement, 3, 1) \ @@ -815,14 +815,20 @@ class Runtime : public AllStatic { // Support getting the characters in a string using [] notation as // in Firefox/SpiderMonkey, Safari and Opera. MUST_USE_RESULT static MaybeHandle GetElementOrCharAt( - Isolate* isolate, Handle object, uint32_t index); + Isolate* isolate, Handle object, uint32_t index, + LanguageMode language_mode = SLOPPY); MUST_USE_RESULT static MaybeHandle SetObjectProperty( Isolate* isolate, Handle object, Handle key, Handle value, LanguageMode language_mode); MUST_USE_RESULT static MaybeHandle GetObjectProperty( - Isolate* isolate, Handle object, Handle key); + Isolate* isolate, Handle object, Handle key, + LanguageMode language_mode = SLOPPY); + + MUST_USE_RESULT static MaybeHandle KeyedGetObjectProperty( + Isolate* isolate, Handle receiver_obj, Handle key_obj, + LanguageMode language_mode); MUST_USE_RESULT static MaybeHandle GetPrototype( Isolate* isolate, Handle object); diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 48a2a88..3b896c5 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -4375,7 +4375,7 @@ void LoadICTrampolineStub::Generate(MacroAssembler* masm) { void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { EmitLoadTypeFeedbackVector(masm, LoadWithVectorDescriptor::VectorRegister()); - KeyedLoadICStub stub(isolate()); + KeyedLoadICStub stub(isolate(), state()); stub.GenerateForTrampoline(masm); } @@ -4554,7 +4554,7 @@ void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); __ j(not_equal, &try_poly_name); Handle megamorphic_stub = - KeyedLoadIC::ChooseMegamorphicStub(masm->isolate()); + KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); __ jmp(megamorphic_stub, RelocInfo::CODE_TARGET); __ bind(&try_poly_name); diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 7560117..abe53ff 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -2196,7 +2196,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ movp(load_receiver, Operand(rsp, kPointerSize)); __ Move(LoadDescriptor::SlotRegister(), SmiFromSlot(expr->KeyedLoadFeedbackSlot())); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code(); CallIC(ic, TypeFeedbackId::None()); __ movp(rdi, rax); __ movp(Operand(rsp, 2 * kPointerSize), rdi); @@ -2364,7 +2364,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { __ Move(LoadDescriptor::NameRegister(), key->value()); __ Move(LoadDescriptor::SlotRegister(), SmiFromSlot(prop->PropertyFeedbackSlot())); - CallLoadIC(NOT_CONTEXTUAL); + CallLoadIC(NOT_CONTEXTUAL, language_mode()); } @@ -2376,13 +2376,14 @@ void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { DCHECK(prop->IsSuperAccess()); __ Push(key->value()); - __ CallRuntime(Runtime::kLoadFromSuper, 3); + __ Push(Smi::FromInt(language_mode())); + __ CallRuntime(Runtime::kLoadFromSuper, 4); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code(); __ Move(LoadDescriptor::SlotRegister(), SmiFromSlot(prop->PropertyFeedbackSlot())); CallIC(ic); @@ -2391,9 +2392,10 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { // Stack: receiver, home_object, key. + __ Push(Smi::FromInt(language_mode())); SetSourcePosition(prop->position()); - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); } @@ -2889,6 +2891,7 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { __ Push(rax); __ Push(Operand(rsp, kPointerSize * 2)); __ Push(key->value()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -2896,7 +2899,8 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadFromSuper, 4); // Replace home_object with target function. __ movp(Operand(rsp, kPointerSize), rax); @@ -2946,6 +2950,7 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { __ Push(rax); __ Push(Operand(rsp, kPointerSize * 2)); VisitForStackValue(prop->key()); + __ Push(Smi::FromInt(language_mode())); // Stack here: // - home_object @@ -2953,7 +2958,8 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); // Replace home_object with target function. __ movp(Operand(rsp, kPointerSize), rax); diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 331584a..20619e6 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -2864,7 +2864,7 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { __ Move(LoadDescriptor::NameRegister(), instr->name()); EmitVectorLoadICRegisters(instr); ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; - Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, + Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, SLOPPY, PREMONOMORPHIC).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -2980,9 +2980,10 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { __ Move(LoadDescriptor::NameRegister(), instr->name()); EmitVectorLoadICRegisters(instr); - Handle ic = CodeFactory::LoadICInOptimizedCode( - isolate(), NOT_CONTEXTUAL, - instr->hydrogen()->initialization_state()).code(); + Handle ic = + CodeFactory::LoadICInOptimizedCode( + isolate(), NOT_CONTEXTUAL, instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3278,9 +3279,9 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { EmitVectorLoadICRegisters(instr); } - Handle ic = - CodeFactory::KeyedLoadICInOptimizedCode( - isolate(), instr->hydrogen()->initialization_state()).code(); + Handle ic = CodeFactory::KeyedLoadICInOptimizedCode( + isolate(), instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/src/x87/code-stubs-x87.cc b/src/x87/code-stubs-x87.cc index cab0000..ccf5173 100644 --- a/src/x87/code-stubs-x87.cc +++ b/src/x87/code-stubs-x87.cc @@ -4090,7 +4090,7 @@ void LoadICTrampolineStub::Generate(MacroAssembler* masm) { void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) { EmitLoadTypeFeedbackVector(masm, LoadWithVectorDescriptor::VectorRegister()); - KeyedLoadICStub stub(isolate()); + KeyedLoadICStub stub(isolate(), state()); stub.GenerateForTrampoline(masm); } @@ -4294,7 +4294,7 @@ void KeyedLoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex); __ j(not_equal, &try_poly_name); Handle megamorphic_stub = - KeyedLoadIC::ChooseMegamorphicStub(masm->isolate()); + KeyedLoadIC::ChooseMegamorphicStub(masm->isolate(), GetExtraICState()); __ jmp(megamorphic_stub, RelocInfo::CODE_TARGET); __ bind(&try_poly_name); diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc index 9798a50..3a3d14d 100644 --- a/src/x87/full-codegen-x87.cc +++ b/src/x87/full-codegen-x87.cc @@ -2157,7 +2157,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ mov(load_receiver, Operand(esp, kPointerSize)); __ mov(LoadDescriptor::SlotRegister(), Immediate(SmiFromSlot(expr->KeyedLoadFeedbackSlot()))); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), SLOPPY).code(); CallIC(ic, TypeFeedbackId::None()); __ mov(edi, eax); __ mov(Operand(esp, 2 * kPointerSize), edi); @@ -2326,7 +2326,7 @@ void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { __ mov(LoadDescriptor::NameRegister(), Immediate(key->value())); __ mov(LoadDescriptor::SlotRegister(), Immediate(SmiFromSlot(prop->PropertyFeedbackSlot()))); - CallLoadIC(NOT_CONTEXTUAL); + CallLoadIC(NOT_CONTEXTUAL, language_mode()); } @@ -2338,13 +2338,14 @@ void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { DCHECK(prop->IsSuperAccess()); __ push(Immediate(key->value())); - __ CallRuntime(Runtime::kLoadFromSuper, 3); + __ push(Immediate(Smi::FromInt(language_mode()))); + __ CallRuntime(Runtime::kLoadFromSuper, 4); } void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { SetSourcePosition(prop->position()); - Handle ic = CodeFactory::KeyedLoadIC(isolate()).code(); + Handle ic = CodeFactory::KeyedLoadIC(isolate(), language_mode()).code(); __ mov(LoadDescriptor::SlotRegister(), Immediate(SmiFromSlot(prop->PropertyFeedbackSlot()))); CallIC(ic); @@ -2353,9 +2354,10 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { // Stack: receiver, home_object, key. + __ push(Immediate(Smi::FromInt(language_mode()))); SetSourcePosition(prop->position()); - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); } @@ -2885,13 +2887,15 @@ void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { __ push(eax); __ push(Operand(esp, kPointerSize * 2)); __ push(Immediate(key->value())); + __ push(Immediate(Smi::FromInt(language_mode()))); // Stack here: // - home_object // - this (receiver) // - this (receiver) <-- LoadFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadFromSuper, 4); // Replace home_object with target function. __ mov(Operand(esp, kPointerSize), eax); @@ -2941,13 +2945,15 @@ void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { __ push(eax); __ push(Operand(esp, kPointerSize * 2)); VisitForStackValue(prop->key()); + __ push(Immediate(Smi::FromInt(language_mode()))); // Stack here: // - home_object // - this (receiver) // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. // - home_object // - key - __ CallRuntime(Runtime::kLoadKeyedFromSuper, 3); + // - language_mode + __ CallRuntime(Runtime::kLoadKeyedFromSuper, 4); // Replace home_object with target function. __ mov(Operand(esp, kPointerSize), eax); diff --git a/src/x87/lithium-codegen-x87.cc b/src/x87/lithium-codegen-x87.cc index e59d256..30ffc15 100644 --- a/src/x87/lithium-codegen-x87.cc +++ b/src/x87/lithium-codegen-x87.cc @@ -3116,7 +3116,7 @@ void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { __ mov(LoadDescriptor::NameRegister(), instr->name()); EmitVectorLoadICRegisters(instr); ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL; - Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, + Handle ic = CodeFactory::LoadICInOptimizedCode(isolate(), mode, SLOPPY, PREMONOMORPHIC).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3226,9 +3226,10 @@ void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { __ mov(LoadDescriptor::NameRegister(), instr->name()); EmitVectorLoadICRegisters(instr); - Handle ic = CodeFactory::LoadICInOptimizedCode( - isolate(), NOT_CONTEXTUAL, - instr->hydrogen()->initialization_state()).code(); + Handle ic = + CodeFactory::LoadICInOptimizedCode( + isolate(), NOT_CONTEXTUAL, instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } @@ -3467,9 +3468,10 @@ void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { EmitVectorLoadICRegisters(instr); } - Handle ic = + Handle ic = Handle ic = CodeFactory::KeyedLoadICInOptimizedCode( - isolate(), instr->hydrogen()->initialization_state()).code(); + isolate(), instr->hydrogen()->language_mode(), + instr->hydrogen()->initialization_state()).code(); CallCode(ic, RelocInfo::CODE_TARGET, instr); } diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 3d8af9f..5c7bac6 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -19356,7 +19356,7 @@ TEST(AccessCheckThrows) { CheckCorrectThrow("other[1]"); CheckCorrectThrow("JSON.stringify(other)"); CheckCorrectThrow("has_own_property(other, 'x')"); - CheckCorrectThrow("%GetProperty(other, 'x')"); + CheckCorrectThrow("%GetProperty(other, 'x', 0)"); CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)"); CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)"); CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); diff --git a/test/mjsunit/strong/functions.js b/test/mjsunit/strong/functions.js index 6956462..a237270 100644 --- a/test/mjsunit/strong/functions.js +++ b/test/mjsunit/strong/functions.js @@ -47,8 +47,8 @@ function* g() {} (function LexicalBindings(global) { assertEquals('function', typeof f); assertEquals('function', typeof g); - assertEquals(undefined, global.f); - assertEquals(undefined, global.g); + assertFalse(global.hasOwnProperty("f")); + assertFalse(global.hasOwnProperty("g")); })(this); (function ImmutableBindings() { diff --git a/test/mjsunit/strong/load-builtins.js b/test/mjsunit/strong/load-builtins.js new file mode 100644 index 0000000..4266cc4 --- /dev/null +++ b/test/mjsunit/strong/load-builtins.js @@ -0,0 +1,42 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --strong-mode --allow-natives-syntax + +function getGlobal() { + return this; +} + +function polluteGlobal() { + bar = 0; +} + +(function() { + "use strict"; + + let builtins = [ + Array, + Object, + Function, + getGlobal() + ]; + + for (let builtin of builtins) { + assertThrows(function(){"use strong"; builtin.foo}, TypeError); + assertThrows(function(){"use strong"; builtin[0]}, TypeError); + assertThrows(function(){"use strong"; builtin[10000]}, TypeError); + builtin.foo = 1; + assertDoesNotThrow(function(){"use strong"; builtin.foo}); + assertThrows(function(){"use strong"; builtin.bar}); + assertThrows(function(){"use strong"; builtin[0]}, TypeError); + assertThrows(function(){"use strong"; builtin[10000]}, TypeError); + builtin[0] = 1; + assertDoesNotThrow(function(){"use strong"; builtin.foo}); + assertThrows(function(){"use strong"; builtin.bar}); + assertDoesNotThrow(function(){"use strong"; builtin[0]}); + assertThrows(function(){"use strong"; builtin[10000]}, TypeError); + } + polluteGlobal(); + assertDoesNotThrow(function(){"use strong"; getGlobal().bar}); +})(); diff --git a/test/mjsunit/strong/load-element-mutate-backing-store.js b/test/mjsunit/strong/load-element-mutate-backing-store.js new file mode 100644 index 0000000..f346502 --- /dev/null +++ b/test/mjsunit/strong/load-element-mutate-backing-store.js @@ -0,0 +1,239 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --strong-mode --allow-natives-syntax + +function getSloppyArguments() { + return arguments; +} + +function getObjects() { + "use strict"; + return [ + {}, + Object(""), + [], + (function(){}), + (class Foo {}), + getSloppyArguments(), + arguments, + new Date(), + ]; +} + +// TODO(conradw): add tests for non-inheritance once semantics are implemented. +function getNonInheritingObjects() { + "use strong"; + return [ + Object(""), + [], + // TODO(conradw): uncomment and correct test once Object.defineProperty is + // fixed. + // new Uint32Array(0) + ]; +} + +function readFromObjectElementSloppy(o) { + return o[0]; +} + +function readFromObjectElementSparseSloppy(o) { + return o[100000]; +} + +function readFromObjectElementNonSmiSloppy(o) { + return o[3000000000]; +} + +function readFromObjectNonIndexSloppy(o) { + return o[5000000000]; +} + +function readFromObjectElementVarSloppy(o) { + var a = 0; + return o[a]; +} + +function readFromObjectElementSparseVarSloppy(o) { + var a = 100000; + return o[a]; +} + +function readFromObjectElementNonSmiVarSloppy(o) { + var a = 3000000000; + return o[a]; +} + +function readFromObjectNonIndexVarSloppy(o) { + var a = 5000000000; + return o[a]; +} + +function readFromObjectElementStrong(o) { + "use strong"; + return o[0]; +} + +function readFromObjectElementSparseStrong(o) { + "use strong"; + return o[100000]; +} + +function readFromObjectElementNonSmiStrong(o) { + "use strong"; + return o[3000000000]; +} + +function readFromObjectNonIndexStrong(o) { + "use strong"; + return o[5000000000]; +} + +function readFromObjectElementLetStrong(o) { + "use strong"; + let a = 0; + return o[a]; +} + +function readFromObjectElementSparseLetStrong(o) { + "use strong"; + let a = 100000; + return o[a]; +} + +function readFromObjectElementNonSmiLetStrong(o) { + "use strong"; + let a = 3000000000; + return o[a]; +} + +function readFromObjectNonIndexLetStrong(o) { + "use strong"; + let a = 5000000000; + return o[a]; +} + +function getDescs(x) { + return [ + {value: x}, + {configurable: true, enumerable: true, writable: true, value: x}, + {configurable: true, enumerable: true, get: (function() {return x}) }, + ]; +} + +function assertStrongSemantics(func, object) { + %DeoptimizeFunction(func); + %ClearFunctionTypeFeedback(func); + assertThrows(function(){func(object)}, TypeError); + assertThrows(function(){func(object)}, TypeError); + assertThrows(function(){func(object)}, TypeError); + %OptimizeFunctionOnNextCall(func); + assertThrows(function(){func(object)}, TypeError); + %DeoptimizeFunction(func); + assertThrows(function(){func(object)}, TypeError); +} + +function assertSloppySemantics(func, object) { + %DeoptimizeFunction(func); + %ClearFunctionTypeFeedback(func); + assertDoesNotThrow(function(){func(object)}); + assertDoesNotThrow(function(){func(object)}); + assertDoesNotThrow(function(){func(object)}); + %OptimizeFunctionOnNextCall(func); + assertDoesNotThrow(function(){func(object)}); + %DeoptimizeFunction(func); + assertDoesNotThrow(function(){func(object)}); +} + +(function () { + "use strict"; + + let goodKeys = [ + "0", + "100000", + "3000000000", + "5000000000" + ] + + let badKeys = [ + "bar", + "1", + "100001", + "3000000001", + "5000000001" + ]; + + let values = [ + "string", + 1, + 100001, + 30000000001, + 50000000001, + NaN, + {}, + undefined + ]; + + let badAccessorDescs = [ + { set: (function(){}) }, + { configurable: true, enumerable: true, set: (function(){}) } + ]; + + let readSloppy = [ + readFromObjectElementSloppy, + readFromObjectElementSparseSloppy, + readFromObjectElementNonSmiSloppy, + readFromObjectNonIndexSloppy, + readFromObjectElementVarSloppy, + readFromObjectElementSparseVarSloppy, + readFromObjectElementNonSmiVarSloppy, + readFromObjectNonIndexVarSloppy + ]; + + let readStrong = [ + readFromObjectElementStrong, + readFromObjectElementSparseStrong, + readFromObjectElementNonSmiStrong, + readFromObjectNonIndexStrong, + readFromObjectElementLetStrong, + readFromObjectElementSparseLetStrong, + readFromObjectElementNonSmiLetStrong, + readFromObjectNonIndexLetStrong + ]; + + let dummyProto = {}; + for (let key of goodKeys) { + Object.defineProperty(dummyProto, key, { value: undefined }); + } + + // After altering the backing store, accessing a missing property should still + // throw. + for (let key of badKeys) { + for (let value of values) { + for (let desc of getDescs(value)) { + let objects = getObjects(); + let nonInheritingObjects = getNonInheritingObjects(); + for (let object of objects.concat(nonInheritingObjects)) { + Object.defineProperty(object, key, desc); + for (let func of readStrong) { + assertStrongSemantics(func, object); + } + for (let func of readSloppy) { + assertSloppySemantics(func, object); + } + } + for (let object of objects) { + // Accessing a property which is on the prototype chain of the object + // should not throw. + object.__proto__ = dummyProto; + for (let key of goodKeys) { + for (let func of readStrong.concat(readSloppy)) { + assertSloppySemantics(func, object); + } + } + } + } + } + } +})(); diff --git a/test/mjsunit/strong/load-element.js b/test/mjsunit/strong/load-element.js new file mode 100644 index 0000000..44c3ed0 --- /dev/null +++ b/test/mjsunit/strong/load-element.js @@ -0,0 +1,264 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --strong-mode --allow-natives-syntax + +function getSloppyArguments() { + return arguments; +} + +function getObjects() { + "use strict"; + return [ + {}, + Object(""), + [], + (function(){}), + (class Foo {}), + getSloppyArguments(), + arguments, + new Date() + ]; +} + +//TODO(conradw): add tests for non-inheritance once semantics are implemented. +function getNonInheritingObjects() { + "use strong"; + return [ + Object(""), + [], + new Uint32Array(0) + ]; +} + +function readFromObjectElementSloppy(o) { + return o[0]; +} + +function readFromObjectElementSparseSloppy(o) { + return o[100000]; +} + +function readFromObjectElementNonSmiSloppy(o) { + return o[3000000000]; +} + +function readFromObjectNonIndexSloppy(o) { + return o[5000000000]; +} + +function readFromObjectElementVarSloppy(o) { + var a = 0; + return o[a]; +} + +function readFromObjectElementSparseVarSloppy(o) { + var a = 100000; + return o[a]; +} + +function readFromObjectElementNonSmiVarSloppy(o) { + var a = 3000000000; + return o[a]; +} + +function readFromObjectNonIndexVarSloppy(o) { + var a = 5000000000; + return o[a]; +} + +function readFromObjectElementStrong(o) { + "use strong"; + return o[0]; +} + +function readFromObjectElementSparseStrong(o) { + "use strong"; + return o[100000]; +} + +function readFromObjectElementNonSmiStrong(o) { + "use strong"; + return o[3000000000]; +} + +function readFromObjectNonIndexStrong(o) { + "use strong"; + return o[5000000000]; +} + +function readFromObjectElementLetStrong(o) { + "use strong"; + let a = 0; + return o[a]; +} + +function readFromObjectElementSparseLetStrong(o) { + "use strong"; + let a = 100000; + return o[a]; +} + +function readFromObjectElementNonSmiLetStrong(o) { + "use strong"; + let a = 3000000000; + return o[a]; +} + +function readFromObjectNonIndexLetStrong(o) { + "use strong"; + let a = 5000000000; + return o[a]; +} + +function getDescs(x) { + return [ + {value: x}, + {configurable: true, enumerable: true, writable: true, value: x}, + {configurable: true, enumerable: true, get: (function() {return x}) }, + ]; +} + +function assertStrongSemantics(func, object) { + %DeoptimizeFunction(func); + %ClearFunctionTypeFeedback(func); + assertThrows(function(){func(object)}, TypeError); + assertThrows(function(){func(object)}, TypeError); + assertThrows(function(){func(object)}, TypeError); + %OptimizeFunctionOnNextCall(func); + assertThrows(function(){func(object)}, TypeError); + %DeoptimizeFunction(func); + assertThrows(function(){func(object)}, TypeError); +} + +function assertSloppySemantics(func, object) { + %DeoptimizeFunction(func); + %ClearFunctionTypeFeedback(func); + assertDoesNotThrow(function(){func(object)}); + assertDoesNotThrow(function(){func(object)}); + assertDoesNotThrow(function(){func(object)}); + %OptimizeFunctionOnNextCall(func); + assertDoesNotThrow(function(){func(object)}); + %DeoptimizeFunction(func); + assertDoesNotThrow(function(){func(object)}); +} + +(function () { + "use strict"; + + let goodKeys = [ + "0", + "100000", + "3000000000", + "5000000000" + ] + + let badKeys = [ + "bar", + "1", + "100001", + "3000000001", + "5000000001" + ]; + + let values = [ + "string", + 1, + 100001, + 30000000001, + 50000000001, + NaN, + {}, + undefined + ]; + + let literals = [0, NaN, true, ""]; + + let badAccessorDescs = [ + { set: (function(){}) }, + { configurable: true, enumerable: true, set: (function(){}) } + ]; + + let readSloppy = [ + readFromObjectElementSloppy, + readFromObjectElementSparseSloppy, + readFromObjectElementNonSmiSloppy, + readFromObjectNonIndexSloppy, + readFromObjectElementVarSloppy, + readFromObjectElementSparseVarSloppy, + readFromObjectElementNonSmiVarSloppy, + readFromObjectNonIndexVarSloppy + ]; + + let readStrong = [ + readFromObjectElementStrong, + readFromObjectElementSparseStrong, + readFromObjectElementNonSmiStrong, + readFromObjectNonIndexStrong, + readFromObjectElementLetStrong, + readFromObjectElementSparseLetStrong, + readFromObjectElementNonSmiLetStrong, + readFromObjectNonIndexLetStrong + ]; + + let dummyProto = {}; + for (let key of goodKeys) { + Object.defineProperty(dummyProto, key, { value: undefined }); + } + + let dummyAccessorProto = {}; + for (let key of goodKeys) { + Object.defineProperty(dummyAccessorProto, key, { set: (function(){}) }) + } + + // String literals/objects should not throw on character index access + assertDoesNotThrow(function() {"use strong"; return "string"[0]; }); + assertDoesNotThrow(function() {"use strong"; return Object("string")[0]; }); + + // Attempting to access a property on an object with no defined properties + // should throw. + for (let object of getObjects().concat(getNonInheritingObjects(), literals)) { + for (let func of readStrong) { + assertStrongSemantics(func, object); + } + for (let func of readSloppy) { + assertSloppySemantics(func, object); + } + } + for (let object of getObjects()) { + // Accessing a property which is on the prototype chain of the object should + // not throw. + object.__proto__ = dummyProto; + for (let key of goodKeys) { + for (let func of readStrong.concat(readSloppy)) { + assertSloppySemantics(func, object); + } + } + } + // Properties with accessor descriptors missing 'get' should throw on access. + for (let desc of badAccessorDescs) { + for (let key of goodKeys) { + for (let object of getObjects()) { + Object.defineProperty(object, key, desc); + for (let func of readStrong) { + assertStrongSemantics(func, object); + } + for (let func of readSloppy) { + assertSloppySemantics(func, object); + } + } + } + } + // The same behaviour should be expected for bad accessor properties on the + // prototype chain. + for (let object of getObjects()) { + object.__proto__ = dummyAccessorProto; + for (let func of readStrong) { + assertStrongSemantics(func, object); + } + for (let func of readSloppy) { + assertSloppySemantics(func, object); + } + } +})(); diff --git a/test/mjsunit/strong/load-property-mutate-backing-store.js b/test/mjsunit/strong/load-property-mutate-backing-store.js new file mode 100644 index 0000000..5ed4553 --- /dev/null +++ b/test/mjsunit/strong/load-property-mutate-backing-store.js @@ -0,0 +1,174 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --strong-mode --allow-natives-syntax + +function getSloppyArguments() { + return arguments; +} + +function getObjects() { + "use strict"; + return [ + {}, + Object(""), + [], + (function(){}), + (class Foo {}), + getSloppyArguments(), + arguments, + new Date(), + // TODO(conradw): uncomment once Object.defineProperty is fixed. + // new Uint32Array(0) + ]; +} + +function readFromObjectSloppy(o) { + return o.foo; +} + +function readFromObjectKeyedSloppy(o) { + return o["foo"]; +} + +function readFromObjectKeyedVarSloppy(o) { + var a = "foo"; + return o[a]; +} + +function readFromObjectKeyedComputedSloppy(o) { + var a = "o"; + return o["fo" + a]; +} + +function readFromObjectStrong(o) { + "use strong"; + return o.foo; +} + +function readFromObjectKeyedStrong(o) { + "use strong"; + return o["foo"]; +} + +function readFromObjectKeyedLetStrong(o) { + "use strong"; + let a = "foo"; + return o[a]; +} + +function readFromObjectKeyedComputedStrong(o) { + "use strong"; + let a = "o"; + return o["fo" + a]; +} + +function getDescs(x) { + return [ + {value: x}, + {configurable: true, enumerable: true, writable: true, value: x}, + {configurable: true, enumerable: true, get: (function() {return x}) }, + ]; +} + +function assertStrongSemantics(func, object) { + %DeoptimizeFunction(func); + %ClearFunctionTypeFeedback(func); + assertThrows(function(){func(object)}, TypeError); + assertThrows(function(){func(object)}, TypeError); + assertThrows(function(){func(object)}, TypeError); + %OptimizeFunctionOnNextCall(func); + assertThrows(function(){func(object)}, TypeError); + %DeoptimizeFunction(func); + assertThrows(function(){func(object)}, TypeError); +} + +function assertSloppySemantics(func, object) { + %DeoptimizeFunction(func); + %ClearFunctionTypeFeedback(func); + assertDoesNotThrow(function(){func(object)}); + assertDoesNotThrow(function(){func(object)}); + assertDoesNotThrow(function(){func(object)}); + %OptimizeFunctionOnNextCall(func); + assertDoesNotThrow(function(){func(object)}); + %DeoptimizeFunction(func); + assertDoesNotThrow(function(){func(object)}); +} + +(function () { + "use strict"; + + let goodKeys = [ + "foo" + ] + + let badKeys = [ + "bar", + "1", + "100001", + "3000000001", + "5000000001" + ]; + + let values = [ + "string", + 1, + 100001, + 30000000001, + 50000000001, + NaN, + {}, + undefined + ]; + + let badAccessorDescs = [ + { set: (function(){}) }, + { configurable: true, enumerable: true, set: (function(){}) } + ]; + + let readSloppy = [ + readFromObjectSloppy, + readFromObjectKeyedSloppy, + readFromObjectKeyedVarSloppy, + readFromObjectKeyedComputedSloppy + ]; + + let readStrong = [ + readFromObjectStrong, + readFromObjectKeyedStrong, + readFromObjectKeyedLetStrong, + readFromObjectKeyedComputedStrong + ]; + + let dummyProto = {}; + for (let key of goodKeys) { + Object.defineProperty(dummyProto, key, { value: undefined }); + } + + // After altering the backing store, accessing a missing property should still + // throw. + for (let key of badKeys) { + for (let value of values) { + for (let desc of getDescs(value)) { + for (let object of getObjects()) { + Object.defineProperty(object, key, desc); + for (let func of readStrong) { + assertStrongSemantics(func, object); + } + for (let func of readSloppy) { + assertSloppySemantics(func, object); + } + // Accessing a property which is on the prototype chain of the object + // should not throw. + object.__proto__ = dummyProto; + for (let key of goodKeys) { + for (let func of readStrong.concat(readSloppy)) { + assertSloppySemantics(func, object); + } + } + } + } + } + } +})(); diff --git a/test/mjsunit/strong/load-property.js b/test/mjsunit/strong/load-property.js new file mode 100644 index 0000000..5c77a3e --- /dev/null +++ b/test/mjsunit/strong/load-property.js @@ -0,0 +1,200 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --strong-mode --allow-natives-syntax + +function getSloppyArguments() { + return arguments; +} + +function getObjects() { + "use strict"; + return [ + {}, + Object(""), + [], + (function(){}), + (class Foo {}), + getSloppyArguments(), + arguments, + new Date(), + new Uint32Array(0) + ]; +} + +function readFromObjectSloppy(o) { + return o.foo; +} + +function readFromObjectKeyedSloppy(o) { + return o["foo"]; +} + +function readFromObjectKeyedVarSloppy(o) { + var a = "foo"; + return o[a]; +} + +function readFromObjectKeyedComputedSloppy(o) { + var a = "o"; + return o["fo" + a]; +} + +function readFromObjectStrong(o) { + "use strong"; + return o.foo; +} + +function readFromObjectKeyedStrong(o) { + "use strong"; + return o["foo"]; +} + +function readFromObjectKeyedLetStrong(o) { + "use strong"; + let a = "foo"; + return o[a]; +} + +function readFromObjectKeyedComputedStrong(o) { + "use strong"; + let a = "o"; + return o["fo" + a]; +} + +function getDescs(x) { + return [ + {value: x}, + {configurable: true, enumerable: true, writable: true, value: x}, + {configurable: true, enumerable: true, get: (function() {return x}) }, + ]; +} + +function assertStrongSemantics(func, object) { + %DeoptimizeFunction(func); + %ClearFunctionTypeFeedback(func); + assertThrows(function(){func(object)}, TypeError); + assertThrows(function(){func(object)}, TypeError); + assertThrows(function(){func(object)}, TypeError); + %OptimizeFunctionOnNextCall(func); + assertThrows(function(){func(object)}, TypeError); + %DeoptimizeFunction(func); + assertThrows(function(){func(object)}, TypeError); +} + +function assertSloppySemantics(func, object) { + %DeoptimizeFunction(func); + %ClearFunctionTypeFeedback(func); + assertDoesNotThrow(function(){func(object)}); + assertDoesNotThrow(function(){func(object)}); + assertDoesNotThrow(function(){func(object)}); + %OptimizeFunctionOnNextCall(func); + assertDoesNotThrow(function(){func(object)}); + %DeoptimizeFunction(func); + assertDoesNotThrow(function(){func(object)}); +} + +(function () { + "use strict"; + + let goodKeys = [ + "foo" + ] + + let badKeys = [ + "bar", + "1", + "100001", + "3000000001", + "5000000001" + ]; + + let values = [ + "string", + 1, + 100001, + 30000000001, + 50000000001, + NaN, + {}, + undefined + ]; + + let literals = [0, NaN, true, "string"]; + + let badAccessorDescs = [ + { set: (function(){}) }, + { configurable: true, enumerable: true, set: (function(){}) } + ]; + + let readSloppy = [ + readFromObjectSloppy, + readFromObjectKeyedSloppy, + readFromObjectKeyedVarSloppy, + readFromObjectKeyedComputedSloppy + ]; + + let readStrong = [ + readFromObjectStrong, + readFromObjectKeyedStrong, + readFromObjectKeyedLetStrong, + readFromObjectKeyedComputedStrong + ]; + + let dummyProto = {}; + for (let key of goodKeys) { + Object.defineProperty(dummyProto, key, { value: undefined }); + } + + let dummyAccessorProto = {}; + for (let key of goodKeys) { + Object.defineProperty(dummyAccessorProto, key, { set: (function(){}) }) + } + + // Attempting to access a property on an object with no defined properties + // should throw. + for (let object of getObjects().concat(literals)) { + for (let func of readStrong) { + assertStrongSemantics(func, object); + } + for (let func of readSloppy) { + assertSloppySemantics(func, object); + } + } + for (let object of getObjects()) { + // Accessing a property which is on the prototype chain of the object should + // not throw. + object.__proto__ = dummyProto; + for (let key of goodKeys) { + for (let func of readStrong.concat(readSloppy)) { + assertSloppySemantics(func, object); + } + } + } + // Properties with accessor descriptors missing 'get' should throw on access. + for (let desc of badAccessorDescs) { + for (let key of goodKeys) { + for (let object of getObjects()) { + Object.defineProperty(object, key, desc); + for (let func of readStrong) { + assertStrongSemantics(func, object); + } + for (let func of readSloppy) { + assertSloppySemantics(func, object); + } + } + } + } + // The same behaviour should be expected for bad accessor properties on the + // prototype chain. + for (let object of getObjects()) { + object.__proto__ = dummyAccessorProto; + for (let func of readStrong) { + assertStrongSemantics(func, object); + } + for (let func of readSloppy) { + assertSloppySemantics(func, object); + } + } +})(); diff --git a/test/unittests/compiler/js-type-feedback-unittest.cc b/test/unittests/compiler/js-type-feedback-unittest.cc index bb257cb..524ea6e 100644 --- a/test/unittests/compiler/js-type-feedback-unittest.cc +++ b/test/unittests/compiler/js-type-feedback-unittest.cc @@ -84,7 +84,7 @@ class JSTypeFeedbackTest : public TypedGraphTest { Unique name = Unique::CreateUninitialized( isolate()->factory()->InternalizeUtf8String(string)); - const Operator* op = javascript()->LoadNamed(name, feedback); + const Operator* op = javascript()->LoadNamed(name, feedback, SLOPPY); Node* load = graph()->NewNode(op, global, vector, context); if (mode == JSTypeFeedbackSpecializer::kDeoptimizationEnabled) { for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op); diff --git a/test/unittests/compiler/js-typed-lowering-unittest.cc b/test/unittests/compiler/js-typed-lowering-unittest.cc index ae6a594..a31988b 100644 --- a/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -650,34 +650,37 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) { NewArrayBuffer(backing_store, sizeof(backing_store)); ResolvedFeedbackSlot feedback; TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { - Handle array = - factory()->NewJSTypedArray(type, buffer, 0, kLength); - int const element_size = static_cast(array->element_size()); - - Node* key = Parameter( - Type::Range(kMinInt / element_size, kMaxInt / element_size, zone())); - Node* base = HeapConstant(array); - Node* vector = UndefinedConstant(); - Node* context = UndefinedConstant(); - Node* effect = graph()->start(); - Node* control = graph()->start(); - Reduction r = Reduce(graph()->NewNode( - javascript()->LoadProperty(feedback), base, key, vector, context, - EmptyFrameState(), EmptyFrameState(), effect, control)); + TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { + Handle array = + factory()->NewJSTypedArray(type, buffer, 0, kLength); + int const element_size = static_cast(array->element_size()); - Matcher offset_matcher = - element_size == 1 - ? key - : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); + Node* key = Parameter( + Type::Range(kMinInt / element_size, kMaxInt / element_size, zone())); + Node* base = HeapConstant(array); + Node* vector = UndefinedConstant(); + Node* context = UndefinedConstant(); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Reduction r = Reduce( + graph()->NewNode(javascript()->LoadProperty(feedback, language_mode), + base, key, vector, context, EmptyFrameState(), + EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsLoadBuffer(BufferAccess(type), - IsIntPtrConstant(bit_cast(&backing_store[0])), - offset_matcher, - IsNumberConstant(array->byte_length()->Number()), effect, - control)); + Matcher offset_matcher = + element_size == 1 + ? key + : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsLoadBuffer(BufferAccess(type), + IsIntPtrConstant(bit_cast(&backing_store[0])), + offset_matcher, + IsNumberConstant(array->byte_length()->Number()), effect, + control)); + } } } @@ -689,29 +692,32 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) { NewArrayBuffer(backing_store, sizeof(backing_store)); ResolvedFeedbackSlot feedback; TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { - Handle array = - factory()->NewJSTypedArray(type, buffer, 0, kLength); - ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); - - int min = random_number_generator()->NextInt(static_cast(kLength)); - int max = random_number_generator()->NextInt(static_cast(kLength)); - if (min > max) std::swap(min, max); - Node* key = Parameter(Type::Range(min, max, zone())); - Node* base = HeapConstant(array); - Node* vector = UndefinedConstant(); - Node* context = UndefinedConstant(); - Node* effect = graph()->start(); - Node* control = graph()->start(); - Reduction r = Reduce(graph()->NewNode( - javascript()->LoadProperty(feedback), base, key, vector, context, - EmptyFrameState(), EmptyFrameState(), effect, control)); + TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { + Handle array = + factory()->NewJSTypedArray(type, buffer, 0, kLength); + ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsLoadElement(access, - IsIntPtrConstant(bit_cast(&backing_store[0])), - key, effect, control)); + int min = random_number_generator()->NextInt(static_cast(kLength)); + int max = random_number_generator()->NextInt(static_cast(kLength)); + if (min > max) std::swap(min, max); + Node* key = Parameter(Type::Range(min, max, zone())); + Node* base = HeapConstant(array); + Node* vector = UndefinedConstant(); + Node* context = UndefinedConstant(); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Reduction r = Reduce( + graph()->NewNode(javascript()->LoadProperty(feedback, language_mode), + base, key, vector, context, EmptyFrameState(), + EmptyFrameState(), effect, control)); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsLoadElement(access, + IsIntPtrConstant(bit_cast(&backing_store[0])), + key, effect, control)); + } } } @@ -885,14 +891,17 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) { Node* effect = graph()->start(); Node* control = graph()->start(); - for (size_t i = 0; i < arraysize(names); i++) { - Unique name = Unique::CreateImmovable(names[i]); - Reduction r = Reduce(graph()->NewNode( - javascript()->LoadNamed(name, feedback), global, vector, context, - EmptyFrameState(), EmptyFrameState(), effect, control)); + TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { + for (size_t i = 0; i < arraysize(names); i++) { + Unique name = Unique::CreateImmovable(names[i]); + Reduction r = Reduce(graph()->NewNode( + javascript()->LoadNamed(name, feedback, language_mode), global, + vector, context, EmptyFrameState(), EmptyFrameState(), effect, + control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), matches[i]); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), matches[i]); + } } } -- 2.7.4