Push version 2.1.1 to trunk.
[ES5] Implemented Object.defineProperty.
Improved profiler support.
Added SetPrototype method in the public V8 API.
Added GetScriptOrigin and GetScriptLineNumber methods to Function objects in the API.
Performance improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@3905 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index 7acf81c..5729d9d 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -152,22 +152,6 @@
}
-static void PushInterceptorArguments(MacroAssembler* masm,
- Register receiver,
- Register holder,
- Register name,
- JSObject* holder_obj) {
- __ push(receiver);
- __ push(holder);
- __ push(name);
- InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
- ASSERT(!Heap::InNewSpace(interceptor));
- __ mov(receiver, Immediate(Handle<Object>(interceptor)));
- __ push(receiver);
- __ push(FieldOperand(receiver, InterceptorInfo::kDataOffset));
-}
-
-
void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
int index,
Register prototype) {
@@ -226,30 +210,32 @@
void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
Register receiver,
- Register scratch,
+ Register scratch1,
+ Register scratch2,
Label* miss) {
- Label load_length, check_wrapper;
+ Label check_wrapper;
// Check if the object is a string leaving the instance type in the
// scratch register.
- GenerateStringCheck(masm, receiver, scratch, miss, &check_wrapper);
+ GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper);
// Load length from the string and convert to a smi.
- __ bind(&load_length);
__ mov(eax, FieldOperand(receiver, String::kLengthOffset));
__ SmiTag(eax);
__ ret(0);
// Check if the object is a JSValue wrapper.
__ bind(&check_wrapper);
- __ cmp(scratch, JS_VALUE_TYPE);
+ __ cmp(scratch1, JS_VALUE_TYPE);
__ j(not_equal, miss, not_taken);
// Check if the wrapped value is a string and load the length
// directly if it is.
- __ mov(receiver, FieldOperand(receiver, JSValue::kValueOffset));
- GenerateStringCheck(masm, receiver, scratch, miss, miss);
- __ jmp(&load_length);
+ __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
+ GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
+ __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
+ __ SmiTag(eax);
+ __ ret(0);
}
@@ -285,20 +271,31 @@
}
+static void PushInterceptorArguments(MacroAssembler* masm,
+ Register receiver,
+ Register holder,
+ Register name,
+ JSObject* holder_obj) {
+ __ push(receiver);
+ __ push(holder);
+ __ push(name);
+ InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor();
+ ASSERT(!Heap::InNewSpace(interceptor));
+ __ mov(receiver, Immediate(Handle<Object>(interceptor)));
+ __ push(receiver);
+ __ push(FieldOperand(receiver, InterceptorInfo::kDataOffset));
+}
+
+
static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
Register receiver,
Register holder,
Register 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(1);
- __ CallStub(&stub);
+ __ CallExternalReference(
+ ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)),
+ 5);
}
@@ -326,7 +323,7 @@
stub_compiler->CheckPrototypes(object, receiver, holder,
scratch1, scratch2, name, miss);
- if (lookup->IsValid() && lookup->IsCacheable()) {
+ if (lookup->IsProperty() && lookup->IsCacheable()) {
compiler->CompileCacheable(masm,
stub_compiler,
receiver,
@@ -362,7 +359,7 @@
LookupResult* lookup,
String* name,
Label* miss_label) {
- AccessorInfo* callback = 0;
+ 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
@@ -479,39 +476,362 @@
};
+// Holds information about possible function call optimizations.
+class CallOptimization BASE_EMBEDDED {
+ public:
+ explicit CallOptimization(LookupResult* lookup)
+ : constant_function_(NULL),
+ is_simple_api_call_(false),
+ expected_receiver_type_(NULL),
+ api_call_info_(NULL) {
+ if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
+
+ // We only optimize constant function calls.
+ if (lookup->type() != CONSTANT_FUNCTION) return;
+
+ Initialize(lookup->GetConstantFunction());
+ }
+
+ explicit CallOptimization(JSFunction* function) {
+ Initialize(function);
+ }
+
+ bool is_constant_call() const {
+ return constant_function_ != NULL;
+ }
+
+ JSFunction* constant_function() const {
+ ASSERT(constant_function_ != NULL);
+ return constant_function_;
+ }
+
+ bool is_simple_api_call() const {
+ return is_simple_api_call_;
+ }
+
+ FunctionTemplateInfo* expected_receiver_type() const {
+ ASSERT(is_simple_api_call_);
+ return expected_receiver_type_;
+ }
+
+ CallHandlerInfo* api_call_info() const {
+ ASSERT(is_simple_api_call_);
+ return api_call_info_;
+ }
+
+ // Returns the depth of the object having the expected type in the
+ // prototype chain between the two arguments.
+ int GetPrototypeDepthOfExpectedType(JSObject* object,
+ JSObject* holder) const {
+ ASSERT(is_simple_api_call_);
+ if (expected_receiver_type_ == NULL) return 0;
+ int depth = 0;
+ while (object != holder) {
+ if (object->IsInstanceOf(expected_receiver_type_)) return depth;
+ object = JSObject::cast(object->GetPrototype());
+ ++depth;
+ }
+ if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
+ return kInvalidProtoDepth;
+ }
+
+ private:
+ void Initialize(JSFunction* function) {
+ if (!function->is_compiled()) return;
+
+ constant_function_ = function;
+ is_simple_api_call_ = false;
+
+ AnalyzePossibleApiFunction(function);
+ }
+
+ // Determines whether the given function can be called using the
+ // fast api call builtin.
+ void AnalyzePossibleApiFunction(JSFunction* function) {
+ SharedFunctionInfo* sfi = function->shared();
+ if (sfi->function_data()->IsUndefined()) return;
+ FunctionTemplateInfo* info =
+ FunctionTemplateInfo::cast(sfi->function_data());
+
+ // Require a C++ callback.
+ if (info->call_code()->IsUndefined()) return;
+ api_call_info_ = CallHandlerInfo::cast(info->call_code());
+
+ // Accept signatures that either have no restrictions at all or
+ // only have restrictions on the receiver.
+ if (!info->signature()->IsUndefined()) {
+ SignatureInfo* signature = SignatureInfo::cast(info->signature());
+ if (!signature->args()->IsUndefined()) return;
+ if (!signature->receiver()->IsUndefined()) {
+ expected_receiver_type_ =
+ FunctionTemplateInfo::cast(signature->receiver());
+ }
+ }
+
+ is_simple_api_call_ = true;
+ }
+
+ JSFunction* constant_function_;
+ bool is_simple_api_call_;
+ FunctionTemplateInfo* expected_receiver_type_;
+ CallHandlerInfo* api_call_info_;
+};
+
+
+// Reserves space for the extra arguments to FastHandleApiCall in the
+// caller's frame.
+//
+// These arguments are set by CheckPrototypes and GenerateFastApiCall.
+static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
+ // ----------- S t a t e -------------
+ // -- esp[0] : return address
+ // -- esp[4] : last argument in the internal frame of the caller
+ // -----------------------------------
+ __ pop(scratch);
+ __ push(Immediate(Smi::FromInt(0)));
+ __ push(Immediate(Smi::FromInt(0)));
+ __ push(Immediate(Smi::FromInt(0)));
+ __ push(Immediate(Smi::FromInt(0)));
+ __ push(scratch);
+}
+
+
+// Undoes the effects of ReserveSpaceForFastApiCall.
+static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) {
+ // ----------- S t a t e -------------
+ // -- esp[0] : return address
+ // -- esp[4] : last fast api call extra argument
+ // -- ...
+ // -- esp[16] : first fast api call extra argument
+ // -- esp[20] : last argument in the internal frame
+ // -----------------------------------
+ __ pop(scratch);
+ __ add(Operand(esp), Immediate(kPointerSize * 4));
+ __ push(scratch);
+}
+
+
+// Generates call to FastHandleApiCall builtin.
+static void GenerateFastApiCall(MacroAssembler* masm,
+ const CallOptimization& optimization,
+ int argc) {
+ // ----------- S t a t e -------------
+ // -- esp[0] : return address
+ // -- esp[4] : object passing the type check
+ // (last fast api call extra argument,
+ // set by CheckPrototypes)
+ // -- esp[8] : api call data
+ // -- esp[12] : api callback
+ // -- esp[16] : api function
+ // (first fast api call extra argument)
+ // -- esp[20] : last argument
+ // -- ...
+ // -- esp[(argc + 5) * 4] : first argument
+ // -- esp[(argc + 6) * 4] : receiver
+ // -----------------------------------
+
+ // Get the function and setup the context.
+ JSFunction* function = optimization.constant_function();
+ __ mov(edi, Immediate(Handle<JSFunction>(function)));
+ __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
+
+ // Pass the additional arguments FastHandleApiCall expects.
+ __ mov(Operand(esp, 4 * kPointerSize), edi);
+ bool info_loaded = false;
+ Object* callback = optimization.api_call_info()->callback();
+ if (Heap::InNewSpace(callback)) {
+ info_loaded = true;
+ __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
+ __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kCallbackOffset));
+ __ mov(Operand(esp, 3 * kPointerSize), ebx);
+ } else {
+ __ mov(Operand(esp, 3 * kPointerSize), Immediate(Handle<Object>(callback)));
+ }
+ Object* call_data = optimization.api_call_info()->data();
+ if (Heap::InNewSpace(call_data)) {
+ if (!info_loaded) {
+ __ mov(ecx, Handle<CallHandlerInfo>(optimization.api_call_info()));
+ }
+ __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset));
+ __ mov(Operand(esp, 2 * kPointerSize), ebx);
+ } else {
+ __ mov(Operand(esp, 2 * kPointerSize),
+ Immediate(Handle<Object>(call_data)));
+ }
+
+ // Set the number of arguments.
+ __ mov(eax, Immediate(argc + 4));
+
+ // Jump to the fast api call builtin (tail call).
+ Handle<Code> code = Handle<Code>(
+ Builtins::builtin(Builtins::FastHandleApiCall));
+ ParameterCount expected(0);
+ __ InvokeCode(code, expected, expected,
+ RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+}
+
+
class CallInterceptorCompiler BASE_EMBEDDED {
public:
- CallInterceptorCompiler(const ParameterCount& arguments, Register name)
- : arguments_(arguments), argc_(arguments.immediate()), name_(name) {}
+ CallInterceptorCompiler(StubCompiler* stub_compiler,
+ const ParameterCount& arguments,
+ Register name)
+ : stub_compiler_(stub_compiler),
+ arguments_(arguments),
+ name_(name) {}
+ void Compile(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);
+
+ CallOptimization optimization(lookup);
+
+ if (optimization.is_constant_call() &&
+ !Top::CanHaveSpecialFunctions(holder)) {
+ CompileCacheable(masm,
+ object,
+ receiver,
+ scratch1,
+ scratch2,
+ holder,
+ lookup,
+ name,
+ optimization,
+ miss);
+ } else {
+ CompileRegular(masm,
+ object,
+ receiver,
+ scratch1,
+ scratch2,
+ name,
+ holder,
+ miss);
+ }
+ }
+
+ private:
void CompileCacheable(MacroAssembler* masm,
- StubCompiler* stub_compiler,
+ JSObject* object,
Register receiver,
- Register holder,
Register scratch1,
Register scratch2,
JSObject* holder_obj,
LookupResult* lookup,
String* name,
+ const CallOptimization& optimization,
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;
+ ASSERT(optimization.is_constant_call());
+ ASSERT(!lookup->holder()->IsGlobalObject());
+
+ int depth1 = kInvalidProtoDepth;
+ int depth2 = kInvalidProtoDepth;
+ bool can_do_fast_api_call = false;
+ if (optimization.is_simple_api_call() &&
+ !lookup->holder()->IsGlobalObject()) {
+ depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj);
+ if (depth1 == kInvalidProtoDepth) {
+ depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj,
+ lookup->holder());
}
+ can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
+ (depth2 != kInvalidProtoDepth);
}
- if (!optimize) {
- CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label);
- return;
+ __ IncrementCounter(&Counters::call_const_interceptor, 1);
+
+ if (can_do_fast_api_call) {
+ __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1);
+ ReserveSpaceForFastApiCall(masm, scratch1);
}
+ Label miss_cleanup;
+ Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
+ Register holder =
+ stub_compiler_->CheckPrototypes(object, receiver, holder_obj,
+ scratch1, scratch2, name,
+ depth1, miss);
+
+ Label regular_invoke;
+ LoadWithInterceptor(masm, receiver, holder, holder_obj, ®ular_invoke);
+
+ // Generate code for the failed interceptor case.
+
+ // Check the lookup is still valid.
+ stub_compiler_->CheckPrototypes(holder_obj, receiver,
+ lookup->holder(),
+ scratch1, scratch2, name,
+ depth2, miss);
+
+ if (can_do_fast_api_call) {
+ GenerateFastApiCall(masm, optimization, arguments_.immediate());
+ } else {
+ __ InvokeFunction(optimization.constant_function(), arguments_,
+ JUMP_FUNCTION);
+ }
+
+ if (can_do_fast_api_call) {
+ __ bind(&miss_cleanup);
+ FreeSpaceForFastApiCall(masm, scratch1);
+ __ jmp(miss_label);
+ }
+
+ __ bind(®ular_invoke);
+ if (can_do_fast_api_call) {
+ FreeSpaceForFastApiCall(masm, scratch1);
+ }
+ }
+
+ void CompileRegular(MacroAssembler* masm,
+ JSObject* object,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ String* name,
+ JSObject* holder_obj,
+ Label* miss_label) {
+ Register holder =
+ stub_compiler_->CheckPrototypes(object, receiver, holder_obj,
+ scratch1, scratch2, name,
+ miss_label);
+
+ __ EnterInternalFrame();
+ // Save the name_ register across the call.
+ __ push(name_);
+
+ PushInterceptorArguments(masm,
+ receiver,
+ holder,
+ name_,
+ holder_obj);
+
+ __ CallExternalReference(
+ ExternalReference(
+ IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),
+ 5);
+
+ // Restore the name_ register.
+ __ pop(name_);
+ __ LeaveInternalFrame();
+ }
+
+ void LoadWithInterceptor(MacroAssembler* masm,
+ Register receiver,
+ Register holder,
+ JSObject* holder_obj,
+ Label* interceptor_succeeded) {
__ EnterInternalFrame();
__ push(holder); // Save the holder.
__ push(name_); // Save the name.
@@ -527,66 +847,11 @@
__ 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).
- Handle<Code> code(function->code());
- ParameterCount expected(function->shared()->formal_parameter_count());
- __ InvokeCode(code, expected, arguments_,
- RelocInfo::CODE_TARGET, JUMP_FUNCTION);
-
- __ bind(&invoke);
+ __ j(not_equal, interceptor_succeeded);
}
- void CompileRegular(MacroAssembler* masm,
- Register receiver,
- Register holder,
- Register scratch,
- JSObject* holder_obj,
- Label* miss_label) {
- __ EnterInternalFrame();
- // Save the name_ register across the call.
- __ push(name_);
-
- PushInterceptorArguments(masm,
- receiver,
- holder,
- name_,
- holder_obj);
-
- ExternalReference ref = ExternalReference(
- IC_Utility(IC::kLoadPropertyWithInterceptorForCall));
- __ mov(eax, Immediate(5));
- __ mov(ebx, Immediate(ref));
-
- CEntryStub stub(1);
- __ CallStub(&stub);
-
- // Restore the name_ register.
- __ pop(name_);
- __ LeaveInternalFrame();
- }
-
- private:
+ StubCompiler* stub_compiler_;
const ParameterCount& arguments_;
- int argc_;
Register name_;
};
@@ -605,8 +870,9 @@
}
+// Both name_reg and receiver_reg are preserved on jumps to miss_label,
+// but may be destroyed if store is successful.
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
- Builtins::Name storage_extend,
JSObject* object,
int index,
Map* transition,
@@ -636,9 +902,13 @@
if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
// The properties must be extended before we can store the value.
// We jump to a runtime call that extends the properties array.
- __ mov(ecx, Immediate(Handle<Map>(transition)));
- Handle<Code> ic(Builtins::builtin(storage_extend));
- __ jmp(ic, RelocInfo::CODE_TARGET);
+ __ pop(scratch); // Return address.
+ __ push(receiver_reg);
+ __ push(Immediate(Handle<Map>(transition)));
+ __ push(eax);
+ __ push(scratch);
+ __ TailCallRuntime(
+ ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage)), 3, 1);
return;
}
@@ -691,10 +961,12 @@
Register holder_reg,
Register scratch,
String* name,
+ int push_at_depth,
Label* miss) {
// Check that the maps haven't changed.
Register result =
- masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
+ masm()->CheckMaps(object, object_reg, holder, holder_reg, scratch,
+ push_at_depth, miss);
// If we've skipped any global objects, it's not enough to verify
// that their maps haven't changed.
@@ -716,7 +988,7 @@
object = JSObject::cast(object->GetPrototype());
}
- // Return the register containin the holder.
+ // Return the register containing the holder.
return result;
}
@@ -887,7 +1159,7 @@
}
-Object* CallStubCompiler::CompileCallField(Object* object,
+Object* CallStubCompiler::CompileCallField(JSObject* object,
JSObject* holder,
int index,
String* name) {
@@ -909,9 +1181,7 @@
__ j(zero, &miss, not_taken);
// Do the right check and compute the holder register.
- Register reg =
- CheckPrototypes(JSObject::cast(object), edx, holder,
- ebx, eax, name, &miss);
+ Register reg = CheckPrototypes(object, edx, holder, ebx, eax, name, &miss);
GenerateFastPropertyLoad(masm(), edi, reg, holder, index);
@@ -969,15 +1239,31 @@
// unless we're doing a receiver map check.
ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
+ CallOptimization optimization(function);
+ int depth = kInvalidProtoDepth;
+
switch (check) {
case RECEIVER_MAP_CHECK:
+ __ IncrementCounter(&Counters::call_const, 1);
+
+ if (optimization.is_simple_api_call() && !object->IsGlobalObject()) {
+ depth = optimization.GetPrototypeDepthOfExpectedType(
+ JSObject::cast(object), holder);
+ }
+
+ if (depth != kInvalidProtoDepth) {
+ __ IncrementCounter(&Counters::call_const_fast_api, 1);
+ ReserveSpaceForFastApiCall(masm(), eax);
+ }
+
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), edx, holder,
- ebx, eax, name, &miss);
+ ebx, eax, name, depth, &miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
if (object->IsGlobalObject()) {
+ ASSERT(depth == kInvalidProtoDepth);
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
__ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
}
@@ -1062,19 +1348,17 @@
UNREACHABLE();
}
- // 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);
+ if (depth != kInvalidProtoDepth) {
+ GenerateFastApiCall(masm(), optimization, argc);
+ } else {
+ __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
+ }
// Handle call cache miss.
__ bind(&miss);
+ if (depth != kInvalidProtoDepth) {
+ FreeSpaceForFastApiCall(masm(), eax);
+ }
Handle<Code> ic = ComputeCallMiss(arguments().immediate());
__ jmp(ic, RelocInfo::CODE_TARGET);
@@ -1087,7 +1371,7 @@
}
-Object* CallStubCompiler::CompileCallInterceptor(Object* object,
+Object* CallStubCompiler::CompileCallInterceptor(JSObject* object,
JSObject* holder,
String* name) {
// ----------- S t a t e -------------
@@ -1108,18 +1392,16 @@
// Get the receiver from the stack.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
- CallInterceptorCompiler compiler(arguments(), ecx);
- CompileLoadInterceptor(&compiler,
- this,
- masm(),
- JSObject::cast(object),
- holder,
- name,
- &lookup,
- edx,
- ebx,
- edi,
- &miss);
+ CallInterceptorCompiler compiler(this, arguments(), ecx);
+ compiler.Compile(masm(),
+ object,
+ holder,
+ name,
+ &lookup,
+ edx,
+ ebx,
+ edi,
+ &miss);
// Restore receiver.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
@@ -1249,7 +1531,6 @@
// Generate store field code. Trashes the name register.
GenerateStoreField(masm(),
- Builtins::StoreIC_ExtendStorage,
object,
index,
transition,
@@ -1423,15 +1704,14 @@
__ j(not_equal, &miss, not_taken);
// Get the object from the stack.
- __ mov(ebx, Operand(esp, 2 * kPointerSize));
+ __ mov(edx, Operand(esp, 2 * kPointerSize));
// Generate store field code. Trashes the name register.
GenerateStoreField(masm(),
- Builtins::KeyedStoreIC_ExtendStorage,
object,
index,
transition,
- ebx, ecx, edx,
+ edx, ecx, ebx,
&miss);
// Handle store cache miss.
@@ -1451,13 +1731,12 @@
int index,
String* name) {
// ----------- S t a t e -------------
+ // -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
- // -- esp[4] : receiver
// -----------------------------------
Label miss;
- __ mov(eax, Operand(esp, kPointerSize));
GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@@ -1472,13 +1751,12 @@
JSObject* holder,
AccessorInfo* callback) {
// ----------- S t a t e -------------
+ // -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
- // -- esp[4] : receiver
// -----------------------------------
Label miss;
- __ mov(eax, Operand(esp, kPointerSize));
Failure* failure = Failure::InternalError();
bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
callback, name, &miss, &failure);
@@ -1497,13 +1775,12 @@
Object* value,
String* name) {
// ----------- S t a t e -------------
+ // -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
- // -- esp[4] : receiver
// -----------------------------------
Label miss;
- __ mov(eax, Operand(esp, kPointerSize));
GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
@@ -1517,16 +1794,15 @@
JSObject* holder,
String* name) {
// ----------- S t a t e -------------
+ // -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
- // -- esp[4] : receiver
// -----------------------------------
Label miss;
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,
@@ -1553,15 +1829,12 @@
String* name,
bool is_dont_delete) {
// ----------- S t a t e -------------
+ // -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
- // -- esp[4] : receiver
// -----------------------------------
Label miss;
- // Get the receiver from the stack.
- __ 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,
// the receiver cannot be a smi.
@@ -1574,19 +1847,20 @@
CheckPrototypes(object, eax, holder, ebx, edx, name, &miss);
// Get the value from the cell.
- __ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
- __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
+ __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
+ __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {
- __ cmp(eax, Factory::the_hole_value());
+ __ cmp(ebx, Factory::the_hole_value());
__ j(equal, &miss, not_taken);
} else if (FLAG_debug_code) {
- __ cmp(eax, Factory::the_hole_value());
+ __ cmp(ebx, Factory::the_hole_value());
__ Check(not_equal, "DontDelete cells can't contain the hole");
}
__ IncrementCounter(&Counters::named_load_global_inline, 1);
+ __ mov(eax, ebx);
__ ret(0);
__ bind(&miss);
@@ -1603,21 +1877,19 @@
JSObject* holder,
int index) {
// ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
// -- esp[0] : return address
- // -- esp[4] : name
- // -- esp[8] : receiver
// -----------------------------------
Label miss;
- __ mov(eax, Operand(esp, kPointerSize));
- __ mov(ecx, Operand(esp, 2 * kPointerSize));
__ IncrementCounter(&Counters::keyed_load_field, 1);
// Check that the name has not changed.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
__ j(not_equal, &miss, not_taken);
- GenerateLoadField(receiver, holder, ecx, ebx, edx, index, name, &miss);
+ GenerateLoadField(receiver, holder, edx, ebx, ecx, index, name, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_field, 1);
@@ -1633,14 +1905,12 @@
JSObject* holder,
AccessorInfo* callback) {
// ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
// -- esp[0] : return address
- // -- esp[4] : name
- // -- esp[8] : receiver
// -----------------------------------
Label miss;
- __ mov(eax, Operand(esp, kPointerSize));
- __ mov(ecx, Operand(esp, 2 * kPointerSize));
__ IncrementCounter(&Counters::keyed_load_callback, 1);
// Check that the name has not changed.
@@ -1648,7 +1918,7 @@
__ j(not_equal, &miss, not_taken);
Failure* failure = Failure::InternalError();
- bool success = GenerateLoadCallback(receiver, holder, ecx, eax, ebx, edx,
+ bool success = GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx,
callback, name, &miss, &failure);
if (!success) return failure;
@@ -1666,21 +1936,19 @@
JSObject* holder,
Object* value) {
// ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
// -- esp[0] : return address
- // -- esp[4] : name
- // -- esp[8] : receiver
// -----------------------------------
Label miss;
- __ 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.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
__ j(not_equal, &miss, not_taken);
- GenerateLoadConstant(receiver, holder, ecx, ebx, edx,
+ GenerateLoadConstant(receiver, holder, edx, ebx, ecx,
value, name, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_constant_function, 1);
@@ -1695,14 +1963,12 @@
JSObject* holder,
String* name) {
// ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
// -- esp[0] : return address
- // -- esp[4] : name
- // -- esp[8] : receiver
// -----------------------------------
Label miss;
- __ mov(eax, Operand(esp, kPointerSize));
- __ mov(ecx, Operand(esp, 2 * kPointerSize));
__ IncrementCounter(&Counters::keyed_load_interceptor, 1);
// Check that the name has not changed.
@@ -1714,9 +1980,9 @@
GenerateLoadInterceptor(receiver,
holder,
&lookup,
- ecx,
- eax,
edx,
+ eax,
+ ecx,
ebx,
name,
&miss);
@@ -1733,21 +1999,19 @@
Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) {
// ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
// -- esp[0] : return address
- // -- esp[4] : name
- // -- esp[8] : receiver
// -----------------------------------
Label miss;
- __ 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.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
__ j(not_equal, &miss, not_taken);
- GenerateLoadArrayLength(masm(), ecx, edx, &miss);
+ GenerateLoadArrayLength(masm(), edx, ecx, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_array_length, 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1759,21 +2023,19 @@
Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
// ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
// -- esp[0] : return address
- // -- esp[4] : name
- // -- esp[8] : receiver
// -----------------------------------
Label miss;
- __ 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.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
__ j(not_equal, &miss, not_taken);
- GenerateLoadStringLength(masm(), ecx, edx, &miss);
+ GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_string_length, 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1785,21 +2047,19 @@
Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
// ----------- S t a t e -------------
+ // -- eax : key
+ // -- edx : receiver
// -- esp[0] : return address
- // -- esp[4] : name
- // -- esp[8] : receiver
// -----------------------------------
Label miss;
- __ 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.
__ cmp(Operand(eax), Immediate(Handle<String>(name)));
__ j(not_equal, &miss, not_taken);
- GenerateLoadFunctionPrototype(masm(), ecx, edx, ebx, &miss);
+ GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss);
__ bind(&miss);
__ DecrementCounter(&Counters::keyed_load_function_prototype, 1);
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);