diff options
Diffstat (limited to 'deps/v8/src/arm/code-stubs-arm.cc')
-rw-r--r-- | deps/v8/src/arm/code-stubs-arm.cc | 344 |
1 files changed, 253 insertions, 91 deletions
diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index 005fb97513..8193816c84 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/v8.h" - #if V8_TARGET_ARCH_ARM #include "src/base/bits.h" @@ -14,8 +12,8 @@ #include "src/ic/ic.h" #include "src/ic/stub-cache.h" #include "src/isolate.h" -#include "src/jsregexp.h" -#include "src/regexp-macro-assembler.h" +#include "src/regexp/jsregexp.h" +#include "src/regexp/regexp-macro-assembler.h" #include "src/runtime/runtime.h" namespace v8 { @@ -33,7 +31,7 @@ static void InitializeArrayConstructorDescriptor( JS_FUNCTION_STUB_MODE); } else { descriptor->Initialize(r0, deopt_handler, constant_stack_parameter_count, - JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS); + JS_FUNCTION_STUB_MODE); } } @@ -49,7 +47,7 @@ static void InitializeInternalArrayConstructorDescriptor( JS_FUNCTION_STUB_MODE); } else { descriptor->Initialize(r0, deopt_handler, constant_stack_parameter_count, - JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS); + JS_FUNCTION_STUB_MODE); } } @@ -255,6 +253,9 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, // Call runtime on identical symbols since we need to throw a TypeError. __ cmp(r4, Operand(SYMBOL_TYPE)); __ b(eq, slow); + // Call runtime on identical SIMD values since we must throw a TypeError. + __ cmp(r4, Operand(SIMD128_VALUE_TYPE)); + __ b(eq, slow); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, since // we need to throw a TypeError. Smis have already been ruled out. @@ -273,6 +274,9 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Label* slow, // Call runtime on identical symbols since we need to throw a TypeError. __ cmp(r4, Operand(SYMBOL_TYPE)); __ b(eq, slow); + // Call runtime on identical SIMD values since we must throw a TypeError. + __ cmp(r4, Operand(SIMD128_VALUE_TYPE)); + __ b(eq, slow); if (is_strong(strength)) { // Call the runtime on anything that is converted in the semantics, // since we need to throw a TypeError. Smis and heap numbers have @@ -675,26 +679,30 @@ void CompareICStub::GenerateGeneric(MacroAssembler* masm) { __ Push(lhs, rhs); // Figure out which native to call and setup the arguments. - Builtins::JavaScript native; - if (cc == eq) { - native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; + if (cc == eq && strict()) { + __ TailCallRuntime(Runtime::kStrictEquals, 2, 1); } else { - native = - is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE; - int ncr; // NaN compare result - if (cc == lt || cc == le) { - ncr = GREATER; + Builtins::JavaScript native; + if (cc == eq) { + native = Builtins::EQUALS; } else { - DCHECK(cc == gt || cc == ge); // remaining cases - ncr = LESS; + native = + is_strong(strength()) ? Builtins::COMPARE_STRONG : Builtins::COMPARE; + int ncr; // NaN compare result + if (cc == lt || cc == le) { + ncr = GREATER; + } else { + DCHECK(cc == gt || cc == ge); // remaining cases + ncr = LESS; + } + __ mov(r0, Operand(Smi::FromInt(ncr))); + __ push(r0); } - __ mov(r0, Operand(Smi::FromInt(ncr))); - __ push(r0); - } - // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) - // tagged as a small integer. - __ InvokeBuiltin(native, JUMP_FUNCTION); + // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) + // tagged as a small integer. + __ InvokeBuiltin(native, JUMP_FUNCTION); + } __ bind(&miss); GenerateMiss(masm); @@ -1583,7 +1591,7 @@ void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { // by calling the runtime system. __ bind(&slow); __ push(r1); - __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); + __ TailCallRuntime(Runtime::kArguments, 1, 1); } @@ -1831,10 +1839,7 @@ void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) { __ Push(receiver, key); // Receiver, key. // Perform tail call to the entry. - __ TailCallExternalReference( - ExternalReference(IC_Utility(IC::kLoadElementWithInterceptor), - masm->isolate()), - 2, 1); + __ TailCallRuntime(Runtime::kLoadElementWithInterceptor, 2, 1); __ bind(&slow); PropertyAccessCompiler::TailCallBuiltin( @@ -2378,32 +2383,41 @@ void RegExpExecStub::Generate(MacroAssembler* masm) { } -static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub) { +static void CallStubInRecordCallTarget(MacroAssembler* masm, CodeStub* stub, + bool is_super) { // r0 : number of arguments to the construct function - // r2 : Feedback vector - // r3 : slot in feedback vector (Smi) // r1 : the function to call + // r2 : feedback vector + // r3 : slot in feedback vector (Smi) + // r4 : original constructor (for IsSuperConstructorCall) FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); // Number-of-arguments register must be smi-tagged to call out. __ SmiTag(r0); __ Push(r3, r2, r1, r0); + if (is_super) { + __ Push(r4); + } __ CallStub(stub); + if (is_super) { + __ Pop(r4); + } __ Pop(r3, r2, r1, r0); __ SmiUntag(r0); } -static void GenerateRecordCallTarget(MacroAssembler* masm) { +static void GenerateRecordCallTarget(MacroAssembler* masm, bool is_super) { // Cache the called function in a feedback vector slot. Cache states // are uninitialized, monomorphic (indicated by a JSFunction), and // megamorphic. // r0 : number of arguments to the construct function // r1 : the function to call - // r2 : Feedback vector + // r2 : feedback vector // r3 : slot in feedback vector (Smi) + // r4 : original constructor (for IsSuperConstructorCall) Label initialize, done, miss, megamorphic, not_array_function; DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()), @@ -2411,23 +2425,23 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { DCHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(masm->isolate()), masm->isolate()->heap()->uninitialized_symbol()); - // Load the cache state into r4. - __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); - __ ldr(r4, FieldMemOperand(r4, FixedArray::kHeaderSize)); + // Load the cache state into r5. + __ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3)); + __ ldr(r5, FieldMemOperand(r5, FixedArray::kHeaderSize)); // A monomorphic cache hit or an already megamorphic state: invoke the // function without changing the state. - // We don't know if r4 is a WeakCell or a Symbol, but it's harmless to read at + // We don't know if r5 is a WeakCell or a Symbol, but it's harmless to read at // this position in a symbol (see static asserts in type-feedback-vector.h). Label check_allocation_site; - Register feedback_map = r5; - Register weak_value = r6; - __ ldr(weak_value, FieldMemOperand(r4, WeakCell::kValueOffset)); + Register feedback_map = r6; + Register weak_value = r9; + __ ldr(weak_value, FieldMemOperand(r5, WeakCell::kValueOffset)); __ cmp(r1, weak_value); __ b(eq, &done); - __ CompareRoot(r4, Heap::kmegamorphic_symbolRootIndex); + __ CompareRoot(r5, Heap::kmegamorphic_symbolRootIndex); __ b(eq, &done); - __ ldr(feedback_map, FieldMemOperand(r4, HeapObject::kMapOffset)); + __ ldr(feedback_map, FieldMemOperand(r5, HeapObject::kMapOffset)); __ CompareRoot(feedback_map, Heap::kWeakCellMapRootIndex); __ b(ne, FLAG_pretenuring_call_new ? &miss : &check_allocation_site); @@ -2445,8 +2459,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { __ b(ne, &miss); // Make sure the function is the Array() function - __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r4); - __ cmp(r1, r4); + __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r5); + __ cmp(r1, r5); __ b(ne, &megamorphic); __ jmp(&done); } @@ -2455,14 +2469,14 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { // A monomorphic miss (i.e, here the cache is not uninitialized) goes // megamorphic. - __ CompareRoot(r4, Heap::kuninitialized_symbolRootIndex); + __ CompareRoot(r5, Heap::kuninitialized_symbolRootIndex); __ b(eq, &initialize); // MegamorphicSentinel is an immortal immovable object (undefined) so no // write-barrier is needed. __ bind(&megamorphic); - __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); + __ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3)); __ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex); - __ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize)); + __ str(ip, FieldMemOperand(r5, FixedArray::kHeaderSize)); __ jmp(&done); // An uninitialized cache is patched with the function @@ -2470,22 +2484,22 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { if (!FLAG_pretenuring_call_new) { // Make sure the function is the Array() function - __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r4); - __ cmp(r1, r4); + __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r5); + __ cmp(r1, r5); __ b(ne, ¬_array_function); // The target function is the Array constructor, // Create an AllocationSite if we don't already have it, store it in the // slot. CreateAllocationSiteStub create_stub(masm->isolate()); - CallStubInRecordCallTarget(masm, &create_stub); + CallStubInRecordCallTarget(masm, &create_stub, is_super); __ b(&done); __ bind(¬_array_function); } CreateWeakCellStub create_stub(masm->isolate()); - CallStubInRecordCallTarget(masm, &create_stub); + CallStubInRecordCallTarget(masm, &create_stub, is_super); __ bind(&done); } @@ -2535,8 +2549,10 @@ static void EmitSlowCase(MacroAssembler* masm, static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) { // Wrap the receiver and patch it back onto the stack. { FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL); - __ Push(r1, r3); - __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); + __ push(r1); + __ mov(r0, r3); + ToObjectStub stub(masm->isolate()); + __ CallStub(&stub); __ pop(r1); } __ str(r0, MemOperand(sp, argc * kPointerSize)); @@ -2607,18 +2623,18 @@ void CallConstructStub::Generate(MacroAssembler* masm) { // r0 : number of arguments // r1 : the function to call // r2 : feedback vector - // r3 : (only if r2 is not the megamorphic symbol) slot in feedback - // vector (Smi) + // r3 : slot in feedback vector (Smi, for RecordCallTarget) + // r4 : original constructor (for IsSuperConstructorCall) Label slow, non_function_call; // Check that the function is not a smi. __ JumpIfSmi(r1, &non_function_call); // Check that the function is a JSFunction. - __ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE); + __ CompareObjectType(r1, r5, r5, JS_FUNCTION_TYPE); __ b(ne, &slow); if (RecordCallTarget()) { - GenerateRecordCallTarget(masm); + GenerateRecordCallTarget(masm, IsSuperConstructorCall()); __ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3)); if (FLAG_pretenuring_call_new) { @@ -2642,9 +2658,7 @@ void CallConstructStub::Generate(MacroAssembler* masm) { // Pass function as original constructor. if (IsSuperConstructorCall()) { - __ mov(r4, Operand(1 * kPointerSize)); - __ add(r4, r4, Operand(r0, LSL, kPointerSizeLog2)); - __ ldr(r3, MemOperand(sp, r4)); + __ mov(r3, r4); } else { __ mov(r3, r1); } @@ -2658,10 +2672,10 @@ void CallConstructStub::Generate(MacroAssembler* masm) { // r0: number of arguments // r1: called object - // r4: object type + // r5: object type Label do_call; __ bind(&slow); - __ cmp(r4, Operand(JS_FUNCTION_PROXY_TYPE)); + __ cmp(r5, Operand(JS_FUNCTION_PROXY_TYPE)); __ b(ne, &non_function_call); __ GetBuiltinFunction(r1, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR); __ jmp(&do_call); @@ -2898,11 +2912,10 @@ void CallICStub::GenerateMiss(MacroAssembler* masm) { __ Push(r1, r2, r3); // Call the entry. - IC::UtilityId id = GetICState() == DEFAULT ? IC::kCallIC_Miss - : IC::kCallIC_Customization_Miss; - - ExternalReference miss = ExternalReference(IC_Utility(id), masm->isolate()); - __ CallExternalReference(miss, 3); + Runtime::FunctionId id = GetICState() == DEFAULT + ? Runtime::kCallIC_Miss + : Runtime::kCallIC_Customization_Miss; + __ CallRuntime(id, 3); // Move result to edi and exit the internal frame. __ mov(r1, r0); @@ -3014,10 +3027,9 @@ void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { // Fast case of Heap::LookupSingleCharacterStringFromCode. STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiShiftSize == 0); - DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCode + 1)); - __ tst(code_, - Operand(kSmiTagMask | - ((~String::kMaxOneByteCharCode) << kSmiTagSize))); + DCHECK(base::bits::IsPowerOfTwo32(String::kMaxOneByteCharCodeU + 1)); + __ tst(code_, Operand(kSmiTagMask | + ((~String::kMaxOneByteCharCodeU) << kSmiTagSize))); __ b(ne, &slow_case_); __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); @@ -3294,7 +3306,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { // Just jump to runtime to create the sub string. __ bind(&runtime); - __ TailCallRuntime(Runtime::kSubStringRT, 3, 1); + __ TailCallRuntime(Runtime::kSubString, 3, 1); __ bind(&single_char); // r0: original string @@ -3481,7 +3493,7 @@ void StringCompareStub::Generate(MacroAssembler* masm) { // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) // tagged as a small integer. __ bind(&runtime); - __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1); + __ TailCallRuntime(Runtime::kStringCompare, 2, 1); } @@ -3762,7 +3774,7 @@ void CompareICStub::GenerateStrings(MacroAssembler* masm) { if (equality) { __ TailCallRuntime(Runtime::kStringEquals, 2, 1); } else { - __ TailCallRuntime(Runtime::kStringCompareRT, 2, 1); + __ TailCallRuntime(Runtime::kStringCompare, 2, 1); } __ bind(&miss); @@ -3814,15 +3826,12 @@ void CompareICStub::GenerateKnownObjects(MacroAssembler* masm) { void CompareICStub::GenerateMiss(MacroAssembler* masm) { { // Call the runtime system in a fresh internal frame. - ExternalReference miss = - ExternalReference(IC_Utility(IC::kCompareIC_Miss), isolate()); - FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); __ Push(r1, r0); __ Push(lr, r1, r0); __ mov(ip, Operand(Smi::FromInt(op()))); __ push(ip); - __ CallExternalReference(miss, 3); + __ CallRuntime(Runtime::kCompareIC_Miss, 3); // Compute the entry point of the rewritten stub. __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); // Restore registers. @@ -3883,7 +3892,7 @@ void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, Register entity_name = scratch0; // Having undefined at this place means the name is not contained. - DCHECK_EQ(kSmiTagSize, 1); + STATIC_ASSERT(kSmiTagSize == 1); Register tmp = properties; __ add(tmp, properties, Operand(index, LSL, 1)); __ ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset)); @@ -3973,8 +3982,8 @@ void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, } __ and_(scratch2, scratch1, Operand(scratch2, LSR, Name::kHashShift)); - // Scale the index by multiplying by the element size. - DCHECK(NameDictionary::kEntrySize == 3); + // Scale the index by multiplying by the entry size. + STATIC_ASSERT(NameDictionary::kEntrySize == 3); // scratch2 = scratch2 * 3. __ add(scratch2, scratch2, Operand(scratch2, LSL, 1)); @@ -4058,10 +4067,10 @@ void NameDictionaryLookupStub::Generate(MacroAssembler* masm) { __ and_(index, mask, Operand(index, LSR, Name::kHashShift)); // Scale the index by multiplying by the entry size. - DCHECK(NameDictionary::kEntrySize == 3); + STATIC_ASSERT(NameDictionary::kEntrySize == 3); __ add(index, index, Operand(index, LSL, 1)); // index *= 3. - DCHECK_EQ(kSmiTagSize, 1); + STATIC_ASSERT(kSmiTagSize == 1); __ add(index, dictionary, Operand(index, LSL, 2)); __ ldr(entry_key, FieldMemOperand(index, kElementsStartOffset)); @@ -4528,7 +4537,7 @@ void LoadICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags( Code::ComputeHandlerFlags(Code::LOAD_IC)); masm->isolate()->stub_cache()->GenerateProbe(masm, Code::LOAD_IC, code_flags, - false, receiver, name, feedback, + receiver, name, feedback, receiver_map, scratch1, r9); __ bind(&miss); @@ -4667,8 +4676,9 @@ void VectorKeyedStoreICStub::GenerateImpl(MacroAssembler* masm, bool in_frame) { void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) { if (masm->isolate()->function_entry_hook() != NULL) { ProfileEntryHookStub stub(masm->isolate()); - int code_size = masm->CallStubSize(&stub) + 2 * Assembler::kInstrSize; - PredictableCodeSizeScope predictable(masm, code_size); + PredictableCodeSizeScope predictable(masm); + predictable.ExpectSize(masm->CallStubSize(&stub) + + 2 * Assembler::kInstrSize); __ push(lr); __ CallStub(&stub); __ pop(lr); @@ -4772,12 +4782,12 @@ static void CreateArrayDispatchOneArgument(MacroAssembler* masm, // sp[0] - last argument Label normal_sequence; if (mode == DONT_OVERRIDE) { - DCHECK(FAST_SMI_ELEMENTS == 0); - DCHECK(FAST_HOLEY_SMI_ELEMENTS == 1); - DCHECK(FAST_ELEMENTS == 2); - DCHECK(FAST_HOLEY_ELEMENTS == 3); - DCHECK(FAST_DOUBLE_ELEMENTS == 4); - DCHECK(FAST_HOLEY_DOUBLE_ELEMENTS == 5); + STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); + STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); + STATIC_ASSERT(FAST_ELEMENTS == 2); + STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3); + STATIC_ASSERT(FAST_DOUBLE_ELEMENTS == 4); + STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5); // is the low bit set? If so, we are holey and that is good. __ tst(r3, Operand(1)); @@ -5051,6 +5061,158 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) { } +void LoadGlobalViaContextStub::Generate(MacroAssembler* masm) { + Register context = cp; + Register result = r0; + Register slot = r2; + + // Go up the context chain to the script context. + for (int i = 0; i < depth(); ++i) { + __ ldr(result, ContextOperand(context, Context::PREVIOUS_INDEX)); + context = result; + } + + // Load the PropertyCell value at the specified slot. + __ add(result, context, Operand(slot, LSL, kPointerSizeLog2)); + __ ldr(result, ContextOperand(result)); + __ ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset)); + + // If the result is not the_hole, return. Otherwise, handle in the runtime. + __ CompareRoot(result, Heap::kTheHoleValueRootIndex); + __ Ret(ne); + + // Fallback to runtime. + __ SmiTag(slot); + __ push(slot); + __ TailCallRuntime(Runtime::kLoadGlobalViaContext, 1, 1); +} + + +void StoreGlobalViaContextStub::Generate(MacroAssembler* masm) { + Register value = r0; + Register slot = r2; + + Register cell = r1; + Register cell_details = r4; + Register cell_value = r5; + Register cell_value_map = r6; + Register scratch = r9; + + Register context = cp; + Register context_temp = cell; + + Label fast_heapobject_case, fast_smi_case, slow_case; + + if (FLAG_debug_code) { + __ CompareRoot(value, Heap::kTheHoleValueRootIndex); + __ Check(ne, kUnexpectedValue); + } + + // Go up the context chain to the script context. + for (int i = 0; i < depth(); i++) { + __ ldr(context_temp, ContextOperand(context, Context::PREVIOUS_INDEX)); + context = context_temp; + } + + // Load the PropertyCell at the specified slot. + __ add(cell, context, Operand(slot, LSL, kPointerSizeLog2)); + __ ldr(cell, ContextOperand(cell)); + + // Load PropertyDetails for the cell (actually only the cell_type and kind). + __ ldr(cell_details, FieldMemOperand(cell, PropertyCell::kDetailsOffset)); + __ SmiUntag(cell_details); + __ and_(cell_details, cell_details, + Operand(PropertyDetails::PropertyCellTypeField::kMask | + PropertyDetails::KindField::kMask | + PropertyDetails::kAttributesReadOnlyMask)); + + // Check if PropertyCell holds mutable data. + Label not_mutable_data; + __ cmp(cell_details, Operand(PropertyDetails::PropertyCellTypeField::encode( + PropertyCellType::kMutable) | + PropertyDetails::KindField::encode(kData))); + __ b(ne, ¬_mutable_data); + __ JumpIfSmi(value, &fast_smi_case); + + __ bind(&fast_heapobject_case); + __ str(value, FieldMemOperand(cell, PropertyCell::kValueOffset)); + // RecordWriteField clobbers the value register, so we copy it before the + // call. + __ mov(r4, Operand(value)); + __ RecordWriteField(cell, PropertyCell::kValueOffset, r4, scratch, + kLRHasNotBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET, + OMIT_SMI_CHECK); + __ Ret(); + + __ bind(¬_mutable_data); + // Check if PropertyCell value matches the new value (relevant for Constant, + // ConstantType and Undefined cells). + Label not_same_value; + __ ldr(cell_value, FieldMemOperand(cell, PropertyCell::kValueOffset)); + __ cmp(cell_value, value); + __ b(ne, ¬_same_value); + + // Make sure the PropertyCell is not marked READ_ONLY. + __ tst(cell_details, Operand(PropertyDetails::kAttributesReadOnlyMask)); + __ b(ne, &slow_case); + + if (FLAG_debug_code) { + Label done; + // This can only be true for Constant, ConstantType and Undefined cells, + // because we never store the_hole via this stub. + __ cmp(cell_details, Operand(PropertyDetails::PropertyCellTypeField::encode( + PropertyCellType::kConstant) | + PropertyDetails::KindField::encode(kData))); + __ b(eq, &done); + __ cmp(cell_details, Operand(PropertyDetails::PropertyCellTypeField::encode( + PropertyCellType::kConstantType) | + PropertyDetails::KindField::encode(kData))); + __ b(eq, &done); + __ cmp(cell_details, Operand(PropertyDetails::PropertyCellTypeField::encode( + PropertyCellType::kUndefined) | + PropertyDetails::KindField::encode(kData))); + __ Check(eq, kUnexpectedValue); + __ bind(&done); + } + __ Ret(); + __ bind(¬_same_value); + + // Check if PropertyCell contains data with constant type (and is not + // READ_ONLY). + __ cmp(cell_details, Operand(PropertyDetails::PropertyCellTypeField::encode( + PropertyCellType::kConstantType) | + PropertyDetails::KindField::encode(kData))); + __ b(ne, &slow_case); + + // Now either both old and new values must be smis or both must be heap + // objects with same map. + Label value_is_heap_object; + __ JumpIfNotSmi(value, &value_is_heap_object); + __ JumpIfNotSmi(cell_value, &slow_case); + // Old and new values are smis, no need for a write barrier here. + __ bind(&fast_smi_case); + __ str(value, FieldMemOperand(cell, PropertyCell::kValueOffset)); + __ Ret(); + + __ bind(&value_is_heap_object); + __ JumpIfSmi(cell_value, &slow_case); + + __ ldr(cell_value_map, FieldMemOperand(cell_value, HeapObject::kMapOffset)); + __ ldr(scratch, FieldMemOperand(value, HeapObject::kMapOffset)); + __ cmp(cell_value_map, scratch); + __ b(eq, &fast_heapobject_case); + + // Fallback to runtime. + __ bind(&slow_case); + __ SmiTag(slot); + __ Push(slot, value); + __ TailCallRuntime(is_strict(language_mode()) + ? Runtime::kStoreGlobalViaContext_Strict + : Runtime::kStoreGlobalViaContext_Sloppy, + 2, 1); +} + + static int AddressOffset(ExternalReference ref0, ExternalReference ref1) { return ref0.address() - ref1.address(); } |