| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 2984 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2995 | 2995 |
| 2996 | 2996 |
| 2997 void InstanceofStub::Generate(MacroAssembler* masm) { | 2997 void InstanceofStub::Generate(MacroAssembler* masm) { |
| 2998 // Stack on entry: | 2998 // Stack on entry: |
| 2999 // jssp[0]: function. | 2999 // jssp[0]: function. |
| 3000 // jssp[8]: object. | 3000 // jssp[8]: object. |
| 3001 // | 3001 // |
| 3002 // Returns result in x0. Zero indicates instanceof, smi 1 indicates not | 3002 // Returns result in x0. Zero indicates instanceof, smi 1 indicates not |
| 3003 // instanceof. | 3003 // instanceof. |
| 3004 | 3004 |
| 3005 // Instanceof supports the kArgsInRegisters flag but not the others, ie. | |
| 3006 // No call site inlining. | |
| 3007 // No return of true/false objects. | |
| 3008 ASSERT((flags_ == kNoFlags) || (flags_ == kArgsInRegisters)); | |
| 3009 | |
| 3010 Register result = x0; | 3005 Register result = x0; |
| 3011 Register function = right(); | 3006 Register function = right(); |
| 3012 Register object = left(); | 3007 Register object = left(); |
| 3008 Register scratch1 = x6; |
| 3009 Register scratch2 = x7; |
| 3010 Register res_true = x8; |
| 3011 Register res_false = x9; |
| 3012 // Only used if there was an inline map check site. (See |
| 3013 // LCodeGen::DoInstanceOfKnownGlobal().) |
| 3014 Register map_check_site = x4; |
| 3015 // Delta for the instructions generated between the inline map check and the |
| 3016 // instruction setting the result. |
| 3017 const int32_t kDeltaToLoadBoolResult = 4 * kInstructionSize; |
| 3018 |
| 3013 Label not_js_object, slow; | 3019 Label not_js_object, slow; |
| 3014 | 3020 |
| 3015 if (!HasArgsInRegisters()) { | 3021 if (!HasArgsInRegisters()) { |
| 3016 __ Pop(function, object); | 3022 __ Pop(function, object); |
| 3017 } | 3023 } |
| 3018 | 3024 |
| 3025 if (ReturnTrueFalseObject()) { |
| 3026 __ LoadTrueFalseRoots(res_true, res_false); |
| 3027 } else { |
| 3028 // This is counter-intuitive, but correct. |
| 3029 __ Mov(res_true, Operand(Smi::FromInt(0))); |
| 3030 __ Mov(res_false, Operand(Smi::FromInt(1))); |
| 3031 } |
| 3032 |
| 3019 // Check that the left hand side is a JS object and load its map as a side | 3033 // Check that the left hand side is a JS object and load its map as a side |
| 3020 // effect. | 3034 // effect. |
| 3021 Register map = x12; | 3035 Register map = x12; |
| 3022 __ JumpIfSmi(object, ¬_js_object); | 3036 __ JumpIfSmi(object, ¬_js_object); |
| 3023 __ IsObjectJSObjectType(object, map, x7, ¬_js_object); | 3037 __ IsObjectJSObjectType(object, map, scratch2, ¬_js_object); |
| 3024 | 3038 |
| 3025 // If there is a call site cache, don't look in the global cache, but do the | 3039 // If there is a call site cache, don't look in the global cache, but do the |
| 3026 // real lookup and update the call site cache. | 3040 // real lookup and update the call site cache. |
| 3027 if (!HasCallSiteInlineCheck()) { | 3041 if (!HasCallSiteInlineCheck()) { |
| 3028 Label miss; | 3042 Label miss; |
| 3029 __ JumpIfNotRoot(function, Heap::kInstanceofCacheFunctionRootIndex, &miss); | 3043 __ JumpIfNotRoot(function, Heap::kInstanceofCacheFunctionRootIndex, &miss); |
| 3030 __ JumpIfNotRoot(map, Heap::kInstanceofCacheMapRootIndex, &miss); | 3044 __ JumpIfNotRoot(map, Heap::kInstanceofCacheMapRootIndex, &miss); |
| 3031 __ LoadRoot(result, Heap::kInstanceofCacheAnswerRootIndex); | 3045 __ LoadRoot(result, Heap::kInstanceofCacheAnswerRootIndex); |
| 3032 __ Ret(); | 3046 __ Ret(); |
| 3033 __ Bind(&miss); | 3047 __ Bind(&miss); |
| 3034 } | 3048 } |
| 3035 | 3049 |
| 3036 // Get the prototype of the function. | 3050 // Get the prototype of the function. |
| 3037 Register prototype = x13; | 3051 Register prototype = x13; |
| 3038 __ TryGetFunctionPrototype(function, prototype, x7, &slow, | 3052 __ TryGetFunctionPrototype(function, prototype, scratch2, &slow, |
| 3039 MacroAssembler::kMissOnBoundFunction); | 3053 MacroAssembler::kMissOnBoundFunction); |
| 3040 | 3054 |
| 3041 // Check that the function prototype is a JS object. | 3055 // Check that the function prototype is a JS object. |
| 3042 __ JumpIfSmi(prototype, &slow); | 3056 __ JumpIfSmi(prototype, &slow); |
| 3043 __ IsObjectJSObjectType(prototype, x6, x7, &slow); | 3057 __ IsObjectJSObjectType(prototype, scratch1, scratch2, &slow); |
| 3044 | 3058 |
| 3045 // Update the global instanceof or call site inlined cache with the current | 3059 // Update the global instanceof or call site inlined cache with the current |
| 3046 // map and function. The cached answer will be set when it is known below. | 3060 // map and function. The cached answer will be set when it is known below. |
| 3047 if (!HasCallSiteInlineCheck()) { | 3061 if (HasCallSiteInlineCheck()) { |
| 3062 // Patch the (relocated) inlined map check. |
| 3063 __ GetRelocatedValueLocation(map_check_site, scratch1); |
| 3064 // We have a cell, so need another level of dereferencing. |
| 3065 __ Ldr(scratch1, MemOperand(scratch1)); |
| 3066 __ Str(map, FieldMemOperand(scratch1, Cell::kValueOffset)); |
| 3067 } else { |
| 3048 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); | 3068 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); |
| 3049 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); | 3069 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); |
| 3050 } else { | |
| 3051 ASM_UNIMPLEMENTED("InstanceofStub inline patching"); | |
| 3052 } | 3070 } |
| 3053 | 3071 |
| 3054 Label return_result; | 3072 Label return_true, return_result; |
| 3055 { | 3073 { |
| 3056 // Loop through the prototype chain looking for the function prototype. | 3074 // Loop through the prototype chain looking for the function prototype. |
| 3057 Register chain_map = x1; | 3075 Register chain_map = x1; |
| 3058 Register chain_prototype = x14; | 3076 Register chain_prototype = x14; |
| 3059 Register null_value = x15; | 3077 Register null_value = x15; |
| 3060 Label loop; | 3078 Label loop; |
| 3061 __ Ldr(chain_prototype, FieldMemOperand(map, Map::kPrototypeOffset)); | 3079 __ Ldr(chain_prototype, FieldMemOperand(map, Map::kPrototypeOffset)); |
| 3062 __ LoadRoot(null_value, Heap::kNullValueRootIndex); | 3080 __ LoadRoot(null_value, Heap::kNullValueRootIndex); |
| 3063 // Speculatively set a result. | 3081 // Speculatively set a result. |
| 3064 __ Mov(result, Operand(Smi::FromInt(1))); | 3082 __ Mov(result, res_false); |
| 3065 | 3083 |
| 3066 __ Bind(&loop); | 3084 __ Bind(&loop); |
| 3067 | 3085 |
| 3068 // If the chain prototype is the object prototype, return smi(0). | 3086 // If the chain prototype is the object prototype, return true. |
| 3069 __ Cmp(chain_prototype, prototype); | 3087 __ Cmp(chain_prototype, prototype); |
| 3070 ASSERT(Smi::FromInt(0) == 0UL); | 3088 __ B(eq, &return_true); |
| 3071 __ CzeroX(result, eq); | |
| 3072 __ B(eq, &return_result); | |
| 3073 | 3089 |
| 3074 // If the chain prototype is null, we've reached the end of the chain, so | 3090 // If the chain prototype is null, we've reached the end of the chain, so |
| 3075 // return smi(1). | 3091 // return false. |
| 3076 __ Cmp(chain_prototype, null_value); | 3092 __ Cmp(chain_prototype, null_value); |
| 3077 __ B(eq, &return_result); | 3093 __ B(eq, &return_result); |
| 3078 | 3094 |
| 3079 // Otherwise, load the next prototype in the chain, and loop. | 3095 // Otherwise, load the next prototype in the chain, and loop. |
| 3080 __ Ldr(chain_map, FieldMemOperand(chain_prototype, HeapObject::kMapOffset)); | 3096 __ Ldr(chain_map, FieldMemOperand(chain_prototype, HeapObject::kMapOffset)); |
| 3081 __ Ldr(chain_prototype, FieldMemOperand(chain_map, Map::kPrototypeOffset)); | 3097 __ Ldr(chain_prototype, FieldMemOperand(chain_map, Map::kPrototypeOffset)); |
| 3082 __ B(&loop); | 3098 __ B(&loop); |
| 3083 } | 3099 } |
| 3084 | 3100 |
| 3085 // Return sequence when no arguments are on the stack. | 3101 // Return sequence when no arguments are on the stack. |
| 3102 // We cannot fall through to here. |
| 3103 __ Bind(&return_true); |
| 3104 __ Mov(result, res_true); |
| 3086 __ Bind(&return_result); | 3105 __ Bind(&return_result); |
| 3087 if (!HasCallSiteInlineCheck()) { | 3106 if (HasCallSiteInlineCheck()) { |
| 3107 ASSERT(ReturnTrueFalseObject()); |
| 3108 __ Add(map_check_site, map_check_site, kDeltaToLoadBoolResult); |
| 3109 __ GetRelocatedValueLocation(map_check_site, scratch2); |
| 3110 __ Str(result, MemOperand(scratch2)); |
| 3111 } else { |
| 3088 __ StoreRoot(result, Heap::kInstanceofCacheAnswerRootIndex); | 3112 __ StoreRoot(result, Heap::kInstanceofCacheAnswerRootIndex); |
| 3089 } else { | |
| 3090 ASM_UNIMPLEMENTED("InstanceofStub call site patcher"); | |
| 3091 } | 3113 } |
| 3092 __ Ret(); | 3114 __ Ret(); |
| 3093 | 3115 |
| 3094 Label object_not_null, object_not_null_or_smi; | 3116 Label object_not_null, object_not_null_or_smi; |
| 3095 | 3117 |
| 3096 __ Bind(¬_js_object); | 3118 __ Bind(¬_js_object); |
| 3097 Register object_type = x14; | 3119 Register object_type = x14; |
| 3098 // x0 result result return register (uninit) | 3120 // x0 result result return register (uninit) |
| 3099 // x10 function pointer to function | 3121 // x10 function pointer to function |
| 3100 // x11 object pointer to object | 3122 // x11 object pointer to object |
| 3101 // x14 object_type type of object (uninit) | 3123 // x14 object_type type of object (uninit) |
| 3102 | 3124 |
| 3103 // Before null, smi and string checks, check that the rhs is a function. | 3125 // Before null, smi and string checks, check that the rhs is a function. |
| 3104 // For a non-function rhs, an exception must be thrown. | 3126 // For a non-function rhs, an exception must be thrown. |
| 3105 __ JumpIfSmi(function, &slow); | 3127 __ JumpIfSmi(function, &slow); |
| 3106 __ JumpIfNotObjectType(function, x6, object_type, JS_FUNCTION_TYPE, &slow); | 3128 __ JumpIfNotObjectType( |
| 3129 function, scratch1, object_type, JS_FUNCTION_TYPE, &slow); |
| 3130 |
| 3131 __ Mov(result, res_false); |
| 3107 | 3132 |
| 3108 // Null is not instance of anything. | 3133 // Null is not instance of anything. |
| 3109 __ Cmp(object_type, Operand(masm->isolate()->factory()->null_value())); | 3134 __ Cmp(object_type, Operand(masm->isolate()->factory()->null_value())); |
| 3110 __ B(ne, &object_not_null); | 3135 __ B(ne, &object_not_null); |
| 3111 __ Mov(result, Operand(Smi::FromInt(1))); | |
| 3112 __ Ret(); | 3136 __ Ret(); |
| 3113 | 3137 |
| 3114 __ Bind(&object_not_null); | 3138 __ Bind(&object_not_null); |
| 3115 // Smi values are not instances of anything. | 3139 // Smi values are not instances of anything. |
| 3116 __ JumpIfNotSmi(object, &object_not_null_or_smi); | 3140 __ JumpIfNotSmi(object, &object_not_null_or_smi); |
| 3117 __ Mov(result, Operand(Smi::FromInt(1))); | |
| 3118 __ Ret(); | 3141 __ Ret(); |
| 3119 | 3142 |
| 3120 __ Bind(&object_not_null_or_smi); | 3143 __ Bind(&object_not_null_or_smi); |
| 3121 // String values are not instances of anything. | 3144 // String values are not instances of anything. |
| 3122 __ IsObjectJSStringType(object, x7, &slow); | 3145 __ IsObjectJSStringType(object, scratch2, &slow); |
| 3123 __ Mov(result, Operand(Smi::FromInt(1))); | |
| 3124 __ Ret(); | 3146 __ Ret(); |
| 3125 | 3147 |
| 3126 // Slow-case. Tail call builtin. | 3148 // Slow-case. Tail call builtin. |
| 3127 __ Bind(&slow); | 3149 __ Bind(&slow); |
| 3128 if (!ReturnTrueFalseObject()) { | 3150 { |
| 3129 FrameScope scope(masm, StackFrame::INTERNAL); | 3151 FrameScope scope(masm, StackFrame::INTERNAL); |
| 3130 // Arguments have either been passed into registers or have been previously | 3152 // Arguments have either been passed into registers or have been previously |
| 3131 // popped. We need to push them before calling builtin. | 3153 // popped. We need to push them before calling builtin. |
| 3132 __ Push(object, function); | 3154 __ Push(object, function); |
| 3133 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); | 3155 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); |
| 3134 } else { | 3156 } |
| 3135 ASM_UNIMPLEMENTED("InstanceofStub call builtin and return object"); | 3157 if (ReturnTrueFalseObject()) { |
| 3158 __ Cmp(result, 0); |
| 3159 __ Csel(result, res_true, res_false, eq); |
| 3136 } | 3160 } |
| 3137 __ Ret(); | 3161 __ Ret(); |
| 3138 } | 3162 } |
| 3139 | 3163 |
| 3140 | 3164 |
| 3141 Register InstanceofStub::left() { | 3165 Register InstanceofStub::left() { |
| 3142 // Object to check (instanceof lhs). | 3166 // Object to check (instanceof lhs). |
| 3143 return x11; | 3167 return x11; |
| 3144 } | 3168 } |
| 3145 | 3169 |
| (...skipping 3894 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7040 __ Bind(&fast_elements_case); | 7064 __ Bind(&fast_elements_case); |
| 7041 GenerateCase(masm, FAST_ELEMENTS); | 7065 GenerateCase(masm, FAST_ELEMENTS); |
| 7042 } | 7066 } |
| 7043 | 7067 |
| 7044 | 7068 |
| 7045 #undef __ | 7069 #undef __ |
| 7046 | 7070 |
| 7047 } } // namespace v8::internal | 7071 } } // namespace v8::internal |
| 7048 | 7072 |
| 7049 #endif // V8_TARGET_ARCH_A64 | 7073 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |