diff options
Diffstat (limited to 'deps/v8/src/arm/stub-cache-arm.cc')
-rw-r--r-- | deps/v8/src/arm/stub-cache-arm.cc | 366 |
1 files changed, 162 insertions, 204 deletions
diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index d82ef21ce0..f1a52e6eaa 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -426,191 +426,6 @@ static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, } -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* interceptor_holder, - LookupResult* lookup, - String* name, - Label* miss_label) { - AccessorInfo* callback = NULL; - 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, interceptor_holder, - miss_label); - return; - } - - // Note: starting a frame here makes GC aware of pointers pushed below. - __ EnterInternalFrame(); - - __ push(receiver); - __ Push(holder, name_); - - // Invoke an interceptor. Note: map checks from receiver to - // interceptor's holder has been compiled before (see a caller - // of this method.) - CompileCallLoadPropertyWithInterceptor(masm, - receiver, - holder, - name_, - interceptor_holder); - - // Check if interceptor provided a value for property. If it's - // the case, return immediately. - Label interceptor_failed; - __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); - __ cmp(r0, scratch1); - __ b(eq, &interceptor_failed); - __ LeaveInternalFrame(); - __ Ret(); - - __ bind(&interceptor_failed); - __ pop(name_); - __ pop(holder); - __ pop(receiver); - - __ LeaveInternalFrame(); - - if (lookup->type() == FIELD) { - // We found FIELD property in prototype chain of interceptor's holder. - // Check that the maps from interceptor's holder to field's holder - // haven't changed... - holder = stub_compiler->CheckPrototypes(interceptor_holder, - holder, - lookup->holder(), - scratch1, - scratch2, - name, - miss_label); - // ... and retrieve a field from field's holder. - stub_compiler->GenerateFastPropertyLoad(masm, - r0, - holder, - lookup->holder(), - lookup->GetFieldIndex()); - __ Ret(); - } else { - // We found CALLBACKS property in prototype chain of interceptor's - // holder. - ASSERT(lookup->type() == CALLBACKS); - ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); - ASSERT(callback != NULL); - ASSERT(callback->getter() != NULL); - - // Prepare for tail call: push receiver to stack. - Label cleanup; - __ push(receiver); - - // Check that the maps from interceptor's holder to callback's holder - // haven't changed. - holder = stub_compiler->CheckPrototypes(interceptor_holder, holder, - lookup->holder(), scratch1, - scratch2, - name, - &cleanup); - - // Continue tail call preparation: push remaining parameters. - __ push(holder); - __ Move(holder, Handle<AccessorInfo>(callback)); - __ push(holder); - __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset)); - __ Push(scratch1, name_); - - // Tail call to runtime. - ExternalReference ref = - ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); - __ TailCallExternalReference(ref, 5, 1); - - // Clean up code: we pushed receiver and need to remove it. - __ bind(&cleanup); - __ pop(scratch2); - } - } - - - void CompileRegular(MacroAssembler* masm, - Register receiver, - Register holder, - Register scratch, - JSObject* interceptor_holder, - Label* miss_label) { - PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); - - ExternalReference ref = ExternalReference( - IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); - __ TailCallExternalReference(ref, 5, 1); - } - - private: - Register name_; -}; - - -static void CompileLoadInterceptor(LoadInterceptorCompiler* 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. - __ BranchOnSmi(receiver, miss); - - // Check that the maps haven't changed. - Register reg = - stub_compiler->CheckPrototypes(object, receiver, holder, - scratch1, scratch2, name, miss); - - if (lookup->IsProperty() && lookup->IsCacheable()) { - compiler->CompileCacheable(masm, - stub_compiler, - receiver, - reg, - scratch1, - scratch2, - holder, - lookup, - name, - miss); - } else { - compiler->CompileRegular(masm, - receiver, - reg, - scratch2, - holder, - miss); - } -} - - // Reserves space for the extra arguments to FastHandleApiCall in the // caller's frame. // @@ -770,9 +585,9 @@ class CallInterceptorCompiler BASE_EMBEDDED { Label miss_cleanup; Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; Register holder = - stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, - scratch1, scratch2, name, - depth1, miss); + stub_compiler_->CheckPrototypes(object, receiver, + interceptor_holder, scratch1, + scratch2, name, depth1, miss); // Invoke an interceptor and if it provides a value, // branch to |regular_invoke|. @@ -785,9 +600,17 @@ class CallInterceptorCompiler BASE_EMBEDDED { // Check that the maps from interceptor's holder to constant function's // holder haven't changed and thus we can use cached constant function. - stub_compiler_->CheckPrototypes(interceptor_holder, receiver, - lookup->holder(), scratch1, - scratch2, name, depth2, miss); + if (interceptor_holder != lookup->holder()) { + stub_compiler_->CheckPrototypes(interceptor_holder, receiver, + lookup->holder(), scratch1, + scratch2, name, depth2, miss); + } else { + // CheckPrototypes has a side effect of fetching a 'holder' + // for API (object which is instanceof for the signature). It's + // safe to omit it here, as if present, it should be fetched + // by the previous CheckPrototypes. + ASSERT(depth2 == kInvalidProtoDepth); + } // Invoke function. if (can_do_fast_api_call) { @@ -1015,7 +838,7 @@ bool StubCompiler::GenerateLoadCallback(JSObject* object, void StubCompiler::GenerateLoadInterceptor(JSObject* object, - JSObject* holder, + JSObject* interceptor_holder, LookupResult* lookup, Register receiver, Register name_reg, @@ -1023,18 +846,133 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, Register scratch2, String* name, Label* miss) { - LoadInterceptorCompiler compiler(name_reg); - CompileLoadInterceptor(&compiler, - this, - masm(), - object, - holder, - name, - lookup, - receiver, - scratch1, - scratch2, - miss); + ASSERT(interceptor_holder->HasNamedInterceptor()); + ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); + + // Check that the receiver isn't a smi. + __ BranchOnSmi(receiver, miss); + + // So far the most popular follow ups for interceptor loads are FIELD + // and CALLBACKS, so inline only them, other cases may be added + // later. + bool compile_followup_inline = false; + if (lookup->IsProperty() && lookup->IsCacheable()) { + if (lookup->type() == FIELD) { + compile_followup_inline = true; + } else if (lookup->type() == CALLBACKS && + lookup->GetCallbackObject()->IsAccessorInfo() && + AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) { + compile_followup_inline = true; + } + } + + if (compile_followup_inline) { + // Compile the interceptor call, followed by inline code to load the + // property from further up the prototype chain if the call fails. + // Check that the maps haven't changed. + Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, + scratch1, scratch2, name, miss); + ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); + + // Save necessary data before invoking an interceptor. + // Requires a frame to make GC aware of pushed pointers. + __ EnterInternalFrame(); + + if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { + // CALLBACKS case needs a receiver to be passed into C++ callback. + __ Push(receiver, holder_reg, name_reg); + } else { + __ Push(holder_reg, name_reg); + } + + // Invoke an interceptor. Note: map checks from receiver to + // interceptor's holder has been compiled before (see a caller + // of this method.) + CompileCallLoadPropertyWithInterceptor(masm(), + receiver, + holder_reg, + name_reg, + interceptor_holder); + + // Check if interceptor provided a value for property. If it's + // the case, return immediately. + Label interceptor_failed; + __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); + __ cmp(r0, scratch1); + __ b(eq, &interceptor_failed); + __ LeaveInternalFrame(); + __ Ret(); + + __ bind(&interceptor_failed); + __ pop(name_reg); + __ pop(holder_reg); + if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { + __ pop(receiver); + } + + __ LeaveInternalFrame(); + + // Check that the maps from interceptor's holder to lookup's holder + // haven't changed. And load lookup's holder into |holder| register. + if (interceptor_holder != lookup->holder()) { + holder_reg = CheckPrototypes(interceptor_holder, + holder_reg, + lookup->holder(), + scratch1, + scratch2, + name, + miss); + } + + if (lookup->type() == FIELD) { + // We found FIELD property in prototype chain of interceptor's holder. + // Retrieve a field from field's holder. + GenerateFastPropertyLoad(masm(), r0, holder_reg, + lookup->holder(), lookup->GetFieldIndex()); + __ Ret(); + } else { + // We found CALLBACKS property in prototype chain of interceptor's + // holder. + ASSERT(lookup->type() == CALLBACKS); + ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); + AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); + ASSERT(callback != NULL); + ASSERT(callback->getter() != NULL); + + // Tail call to runtime. + // Important invariant in CALLBACKS case: the code above must be + // structured to never clobber |receiver| register. + __ Move(scratch2, Handle<AccessorInfo>(callback)); + // holder_reg is either receiver or scratch1. + if (!receiver.is(holder_reg)) { + ASSERT(scratch1.is(holder_reg)); + __ Push(receiver, holder_reg, scratch2); + __ ldr(scratch1, + FieldMemOperand(holder_reg, AccessorInfo::kDataOffset)); + __ Push(scratch1, name_reg); + } else { + __ push(receiver); + __ ldr(scratch1, + FieldMemOperand(holder_reg, AccessorInfo::kDataOffset)); + __ Push(holder_reg, scratch2, scratch1, name_reg); + } + + ExternalReference ref = + ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); + __ TailCallExternalReference(ref, 5, 1); + } + } else { // !compile_followup_inline + // Call the runtime system to load the interceptor. + // Check that the maps haven't changed. + Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, + scratch1, scratch2, name, miss); + PushInterceptorArguments(masm(), receiver, holder_reg, + name_reg, interceptor_holder); + + ExternalReference ref = ExternalReference( + IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); + __ TailCallExternalReference(ref, 5, 1); + } } @@ -1204,6 +1142,26 @@ Object* CallStubCompiler::CompileArrayPopCall(Object* object, } +Object* CallStubCompiler::CompileStringCharCodeAtCall(Object* object, + JSObject* holder, + JSFunction* function, + String* name, + CheckType check) { + // TODO(722): implement this. + return Heap::undefined_value(); +} + + +Object* CallStubCompiler::CompileStringCharAtCall(Object* object, + JSObject* holder, + JSFunction* function, + String* name, + CheckType check) { + // TODO(722): implement this. + return Heap::undefined_value(); +} + + Object* CallStubCompiler::CompileCallConstant(Object* object, JSObject* holder, JSFunction* function, |