diff options
Diffstat (limited to 'V8Binding/v8/src/ia32/stub-cache-ia32.cc')
-rw-r--r-- | V8Binding/v8/src/ia32/stub-cache-ia32.cc | 500 |
1 files changed, 404 insertions, 96 deletions
diff --git a/V8Binding/v8/src/ia32/stub-cache-ia32.cc b/V8Binding/v8/src/ia32/stub-cache-ia32.cc index e47ad1c..a626377 100644 --- a/V8Binding/v8/src/ia32/stub-cache-ia32.cc +++ b/V8Binding/v8/src/ia32/stub-cache-ia32.cc @@ -152,6 +152,22 @@ void StubCache::GenerateProbe(MacroAssembler* masm, } +template <typename Pushable> +static void PushInterceptorArguments(MacroAssembler* masm, + Register receiver, + Register holder, + Pushable name, + JSObject* holder_obj) { + __ push(receiver); + __ push(holder); + __ push(name); + InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); + __ mov(receiver, Immediate(Handle<Object>(interceptor))); + __ push(receiver); + __ push(FieldOperand(receiver, InterceptorInfo::kDataOffset)); +} + + void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, int index, Register prototype) { @@ -273,6 +289,322 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, } +template <class Pushable> +static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, + Register receiver, + Register holder, + Pushable name, + JSObject* holder_obj) { + PushInterceptorArguments(masm, receiver, holder, name, holder_obj); + + ExternalReference ref = + ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)); + __ mov(eax, Immediate(5)); + __ mov(ebx, Immediate(ref)); + + CEntryStub stub; + __ CallStub(&stub); +} + + +template <class Compiler> +static void CompileLoadInterceptor(Compiler* compiler, + StubCompiler* stub_compiler, + MacroAssembler* masm, + JSObject* object, + JSObject* holder, + String* name, + LookupResult* lookup, + Register receiver, + Register scratch1, + Register scratch2, + Label* miss) { + ASSERT(holder->HasNamedInterceptor()); + ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); + + // Check that the receiver isn't a smi. + __ test(receiver, Immediate(kSmiTagMask)); + __ j(zero, miss, not_taken); + + // Check that the maps haven't changed. + Register reg = + stub_compiler->CheckPrototypes(object, receiver, holder, + scratch1, scratch2, name, miss); + + if (lookup->IsValid() && lookup->IsCacheable()) { + compiler->CompileCacheable(masm, + stub_compiler, + receiver, + reg, + scratch1, + scratch2, + holder, + lookup, + name, + miss); + } else { + compiler->CompileRegular(masm, + receiver, + reg, + scratch2, + holder, + miss); + } +} + + +static void LookupPostInterceptor(JSObject* holder, + String* name, + LookupResult* lookup) { + holder->LocalLookupRealNamedProperty(name, lookup); + if (lookup->IsNotFound()) { + Object* proto = holder->GetPrototype(); + if (proto != Heap::null_value()) { + proto->Lookup(name, lookup); + } + } +} + + +class LoadInterceptorCompiler BASE_EMBEDDED { + public: + explicit LoadInterceptorCompiler(Register name) : name_(name) {} + + void CompileCacheable(MacroAssembler* masm, + StubCompiler* stub_compiler, + Register receiver, + Register holder, + Register scratch1, + Register scratch2, + JSObject* holder_obj, + LookupResult* lookup, + String* name, + Label* miss_label) { + AccessorInfo* callback = 0; + bool optimize = false; + // So far the most popular follow ups for interceptor loads are FIELD + // and CALLBACKS, so inline only them, other cases may be added + // later. + if (lookup->type() == FIELD) { + optimize = true; + } else if (lookup->type() == CALLBACKS) { + Object* callback_object = lookup->GetCallbackObject(); + if (callback_object->IsAccessorInfo()) { + callback = AccessorInfo::cast(callback_object); + optimize = callback->getter() != NULL; + } + } + + if (!optimize) { + CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); + return; + } + + // Note: starting a frame here makes GC aware of pointers pushed below. + __ EnterInternalFrame(); + + if (lookup->type() == CALLBACKS) { + __ push(receiver); + } + __ push(holder); + __ push(name_); + + CompileCallLoadPropertyWithInterceptor(masm, + receiver, + holder, + name_, + holder_obj); + + Label interceptor_failed; + __ cmp(eax, Factory::no_interceptor_result_sentinel()); + __ j(equal, &interceptor_failed); + __ LeaveInternalFrame(); + __ ret(0); + + __ bind(&interceptor_failed); + __ pop(name_); + __ pop(holder); + if (lookup->type() == CALLBACKS) { + __ pop(receiver); + } + + __ LeaveInternalFrame(); + + if (lookup->type() == FIELD) { + holder = stub_compiler->CheckPrototypes(holder_obj, holder, + lookup->holder(), scratch1, + scratch2, + name, + miss_label); + stub_compiler->GenerateFastPropertyLoad(masm, eax, + holder, lookup->holder(), + lookup->GetFieldIndex()); + __ ret(0); + } else { + ASSERT(lookup->type() == CALLBACKS); + ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); + ASSERT(callback != NULL); + ASSERT(callback->getter() != NULL); + + Label cleanup; + __ pop(scratch2); + __ push(receiver); + __ push(scratch2); + + holder = stub_compiler->CheckPrototypes(holder_obj, holder, + lookup->holder(), scratch1, + scratch2, + name, + &cleanup); + + __ pop(scratch2); // save old return address + __ push(holder); + __ mov(holder, Immediate(Handle<AccessorInfo>(callback))); + __ push(holder); + __ push(FieldOperand(holder, AccessorInfo::kDataOffset)); + __ push(name_); + __ push(scratch2); // restore old return address + + ExternalReference ref = + ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); + __ TailCallRuntime(ref, 5); + + __ bind(&cleanup); + __ pop(scratch1); + __ pop(scratch2); + __ push(scratch1); + } + } + + + void CompileRegular(MacroAssembler* masm, + Register receiver, + Register holder, + Register scratch, + JSObject* holder_obj, + Label* miss_label) { + __ pop(scratch); // save old return address + PushInterceptorArguments(masm, receiver, holder, name_, holder_obj); + __ push(scratch); // restore old return address + + ExternalReference ref = ExternalReference( + IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); + __ TailCallRuntime(ref, 5); + } + + private: + Register name_; +}; + + +class CallInterceptorCompiler BASE_EMBEDDED { + public: + explicit CallInterceptorCompiler(const ParameterCount& arguments) + : arguments_(arguments), argc_(arguments.immediate()) {} + + void CompileCacheable(MacroAssembler* masm, + StubCompiler* stub_compiler, + Register receiver, + Register holder, + Register scratch1, + Register scratch2, + JSObject* holder_obj, + LookupResult* lookup, + String* name, + Label* miss_label) { + JSFunction* function = 0; + bool optimize = false; + // So far the most popular case for failed interceptor is + // CONSTANT_FUNCTION sitting below. + if (lookup->type() == CONSTANT_FUNCTION) { + function = lookup->GetConstantFunction(); + // JSArray holder is a special case for call constant function + // (see the corresponding code). + if (function->is_compiled() && !holder_obj->IsJSArray()) { + optimize = true; + } + } + + if (!optimize) { + CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); + return; + } + + __ EnterInternalFrame(); + __ push(holder); // save the holder + + CompileCallLoadPropertyWithInterceptor( + masm, + receiver, + holder, + // Under EnterInternalFrame this refers to name. + Operand(ebp, (argc_ + 3) * kPointerSize), + holder_obj); + + __ pop(receiver); // restore holder + __ LeaveInternalFrame(); + + __ cmp(eax, Factory::no_interceptor_result_sentinel()); + Label invoke; + __ j(not_equal, &invoke); + + stub_compiler->CheckPrototypes(holder_obj, receiver, + lookup->holder(), scratch1, + scratch2, + name, + miss_label); + if (lookup->holder()->IsGlobalObject()) { + __ mov(edx, Operand(esp, (argc_ + 1) * kPointerSize)); + __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); + __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx); + } + + ASSERT(function->is_compiled()); + // Get the function and setup the context. + __ mov(edi, Immediate(Handle<JSFunction>(function))); + __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); + + // Jump to the cached code (tail call). + ASSERT(function->is_compiled()); + Handle<Code> code(function->code()); + ParameterCount expected(function->shared()->formal_parameter_count()); + __ InvokeCode(code, expected, arguments_, + RelocInfo::CODE_TARGET, JUMP_FUNCTION); + + __ bind(&invoke); + } + + void CompileRegular(MacroAssembler* masm, + Register receiver, + Register holder, + Register scratch, + JSObject* holder_obj, + Label* miss_label) { + __ EnterInternalFrame(); + + PushInterceptorArguments(masm, + receiver, + holder, + Operand(ebp, (argc_ + 3) * kPointerSize), + holder_obj); + + ExternalReference ref = ExternalReference( + IC_Utility(IC::kLoadPropertyWithInterceptorForCall)); + __ mov(eax, Immediate(5)); + __ mov(ebx, Immediate(ref)); + + CEntryStub stub; + __ CallStub(&stub); + + __ LeaveInternalFrame(); + } + + private: + const ParameterCount& arguments_; + int argc_; +}; + + void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); Code* code = NULL; @@ -447,15 +779,17 @@ void StubCompiler::GenerateLoadCallback(JSObject* object, // Push the arguments on the JS stack of the caller. __ pop(scratch2); // remove return address __ push(receiver); // receiver - __ push(Immediate(Handle<AccessorInfo>(callback))); // callback data - __ push(name_reg); // name __ push(reg); // holder + __ mov(reg, Immediate(Handle<AccessorInfo>(callback))); // callback data + __ push(reg); + __ push(FieldOperand(reg, AccessorInfo::kDataOffset)); + __ push(name_reg); // name __ push(scratch2); // restore return address // Do tail-call to the runtime system. ExternalReference load_callback_property = ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); - __ TailCallRuntime(load_callback_property, 4); + __ TailCallRuntime(load_callback_property, 5); } @@ -484,36 +818,25 @@ void StubCompiler::GenerateLoadConstant(JSObject* object, void StubCompiler::GenerateLoadInterceptor(JSObject* object, JSObject* holder, - Smi* lookup_hint, + LookupResult* lookup, Register receiver, Register name_reg, Register scratch1, Register scratch2, String* name, Label* miss) { - // Check that the receiver isn't a smi. - __ test(receiver, Immediate(kSmiTagMask)); - __ j(zero, miss, not_taken); - - // Check that the maps haven't changed. - Register reg = - CheckPrototypes(object, receiver, holder, - scratch1, scratch2, name, miss); - - // Push the arguments on the JS stack of the caller. - __ pop(scratch2); // remove return address - __ push(receiver); // receiver - __ push(reg); // holder - __ push(name_reg); // name - // TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or - // LOOKUP_IN_PROTOTYPE, but use a special version of lookup method? - __ push(Immediate(lookup_hint)); - __ push(scratch2); // restore return address - - // Do tail-call to the runtime system. - ExternalReference load_ic_property = - ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)); - __ TailCallRuntime(load_ic_property, 4); + LoadInterceptorCompiler compiler(name_reg); + CompileLoadInterceptor(&compiler, + this, + masm(), + object, + holder, + name, + lookup, + receiver, + scratch1, + scratch2, + miss); } @@ -678,13 +1001,13 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, case JSARRAY_HAS_FAST_ELEMENTS_CHECK: CheckPrototypes(JSObject::cast(object), edx, holder, ebx, ecx, name, &miss); - // Make sure object->elements()->map() != Heap::dictionary_array_map() + // Make sure object->HasFastElements(). // Get the elements array of the object. __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); // Check that the object is in fast mode (not dictionary). __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), - Immediate(Factory::hash_table_map())); - __ j(equal, &miss, not_taken); + Immediate(Factory::fixed_array_map())); + __ j(not_equal, &miss, not_taken); break; default: @@ -726,47 +1049,32 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, // Get the number of arguments. const int argc = arguments().immediate(); + LookupResult lookup; + LookupPostInterceptor(holder, name, &lookup); + // Get the receiver from the stack. __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); - // Check that the receiver isn't a smi. - __ test(edx, Immediate(kSmiTagMask)); - __ j(zero, &miss, not_taken); - - // Check that maps have not changed and compute the holder register. - Register reg = - CheckPrototypes(JSObject::cast(object), edx, holder, - ebx, ecx, name, &miss); - - // Enter an internal frame. - __ EnterInternalFrame(); - - // Push arguments on the expression stack. - __ push(edx); // receiver - __ push(reg); // holder - __ push(Operand(ebp, (argc + 3) * kPointerSize)); // name - __ push(Immediate(holder->InterceptorPropertyLookupHint(name))); - - // Perform call. - ExternalReference load_interceptor = - ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)); - __ mov(eax, Immediate(4)); - __ mov(ebx, Immediate(load_interceptor)); - - CEntryStub stub; - __ CallStub(&stub); - - // Move result to edi and restore receiver. - __ mov(edi, eax); - __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver - - // Exit frame. - __ LeaveInternalFrame(); + CallInterceptorCompiler compiler(arguments()); + CompileLoadInterceptor(&compiler, + this, + masm(), + JSObject::cast(object), + holder, + name, + &lookup, + edx, + ebx, + ecx, + &miss); + + // Restore receiver. + __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // Check that the function really is a function. - __ test(edi, Immediate(kSmiTagMask)); + __ test(eax, Immediate(kSmiTagMask)); __ j(zero, &miss, not_taken); - __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); + __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); __ j(not_equal, &miss, not_taken); // Patch the receiver on the stack with the global proxy if @@ -777,6 +1085,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, } // Invoke the function. + __ mov(edi, eax); __ InvokeFunction(edi, arguments(), JUMP_FUNCTION); // Handle load cache miss. @@ -798,8 +1107,6 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, // ----------------------------------- Label miss; - __ IncrementCounter(&Counters::call_global_inline, 1); - // Get the number of arguments. const int argc = arguments().immediate(); @@ -835,6 +1142,7 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); // Jump to the cached code (tail call). + __ IncrementCounter(&Counters::call_global_inline, 1); ASSERT(function->is_compiled()); Handle<Code> code(function->code()); ParameterCount expected(function->shared()->formal_parameter_count()); @@ -843,7 +1151,6 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, // Handle call cache miss. __ bind(&miss); - __ DecrementCounter(&Counters::call_global_inline, 1); __ IncrementCounter(&Counters::call_global_inline_miss, 1); Handle<Code> ic = ComputeCallMiss(arguments().immediate()); __ jmp(ic, RelocInfo::CODE_TARGET); @@ -1007,10 +1314,8 @@ Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, // ----------------------------------- Label miss; - __ IncrementCounter(&Counters::named_store_global_inline, 1); - // Check that the map of the global has not changed. - __ mov(ebx, (Operand(esp, kPointerSize))); + __ mov(ebx, Operand(esp, kPointerSize)); __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), Immediate(Handle<Map>(object->map()))); __ j(not_equal, &miss, not_taken); @@ -1020,11 +1325,11 @@ Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax); // Return the value (register eax). + __ IncrementCounter(&Counters::named_store_global_inline, 1); __ ret(0); // Handle store cache miss. __ bind(&miss); - __ DecrementCounter(&Counters::named_store_global_inline, 1); __ IncrementCounter(&Counters::named_store_global_inline_miss, 1); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); __ jmp(ic, RelocInfo::CODE_TARGET); @@ -1089,7 +1394,7 @@ Object* LoadStubCompiler::CompileLoadField(JSObject* object, // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss); __ bind(&miss); GenerateLoadMiss(masm(), Code::LOAD_IC); @@ -1110,7 +1415,7 @@ Object* LoadStubCompiler::CompileLoadCallback(JSObject* object, // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, callback, name, &miss); __ bind(&miss); @@ -1132,7 +1437,7 @@ Object* LoadStubCompiler::CompileLoadConstant(JSObject* object, // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss); __ bind(&miss); GenerateLoadMiss(masm(), Code::LOAD_IC); @@ -1152,12 +1457,15 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); + LookupResult lookup; + LookupPostInterceptor(holder, name, &lookup); + + __ mov(eax, Operand(esp, kPointerSize)); // TODO(368): Compile in the whole chain: all the interceptors in // prototypes and ultimate answer. GenerateLoadInterceptor(receiver, holder, - holder->InterceptorPropertyLookupHint(name), + &lookup, eax, ecx, edx, @@ -1185,10 +1493,8 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object, // ----------------------------------- Label miss; - __ IncrementCounter(&Counters::named_load_global_inline, 1); - // Get the receiver from the stack. - __ mov(eax, (Operand(esp, kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); // If the object is the holder then we know that it's a global // object which can only happen for contextual loads. In this case, @@ -1214,10 +1520,10 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object, __ Check(not_equal, "DontDelete cells can't contain the hole"); } + __ IncrementCounter(&Counters::named_load_global_inline, 1); __ ret(0); __ bind(&miss); - __ DecrementCounter(&Counters::named_load_global_inline, 1); __ IncrementCounter(&Counters::named_load_global_inline_miss, 1); GenerateLoadMiss(masm(), Code::LOAD_IC); @@ -1237,8 +1543,8 @@ Object* KeyedLoadStubCompiler::CompileLoadField(String* name, // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); - __ mov(ecx, (Operand(esp, 2 * kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); + __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_field, 1); // Check that the name has not changed. @@ -1267,8 +1573,8 @@ Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name, // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); - __ mov(ecx, (Operand(esp, 2 * kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); + __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_callback, 1); // Check that the name has not changed. @@ -1297,8 +1603,8 @@ Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name, // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); - __ mov(ecx, (Operand(esp, 2 * kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); + __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_constant_function, 1); // Check that the name has not changed. @@ -1326,17 +1632,19 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); - __ mov(ecx, (Operand(esp, 2 * kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); + __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_interceptor, 1); // Check that the name has not changed. __ cmp(Operand(eax), Immediate(Handle<String>(name))); __ j(not_equal, &miss, not_taken); + LookupResult lookup; + LookupPostInterceptor(holder, name, &lookup); GenerateLoadInterceptor(receiver, holder, - Smi::FromInt(JSObject::kLookupInHolder), + &lookup, ecx, eax, edx, @@ -1362,8 +1670,8 @@ Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); - __ mov(ecx, (Operand(esp, 2 * kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); + __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_array_length, 1); // Check that the name has not changed. @@ -1388,8 +1696,8 @@ Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); - __ mov(ecx, (Operand(esp, 2 * kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); + __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_string_length, 1); // Check that the name has not changed. @@ -1414,8 +1722,8 @@ Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { // ----------------------------------- Label miss; - __ mov(eax, (Operand(esp, kPointerSize))); - __ mov(ecx, (Operand(esp, 2 * kPointerSize))); + __ mov(eax, Operand(esp, kPointerSize)); + __ mov(ecx, Operand(esp, 2 * kPointerSize)); __ IncrementCounter(&Counters::keyed_load_function_prototype, 1); // Check that the name has not changed. |