From 2982f5e3200ee860a4ff84f382704710230ff4f6 Mon Sep 17 00:00:00 2001 From: "ricow@chromium.org" Date: Fri, 20 Aug 2010 07:10:18 +0000 Subject: [PATCH] Change code pointer in function objects to a pointer to the first instruction. By changing the pointer to the code object to a pointer to the first instruction we can call directly this instruction directly instead of looking up the address through the code object. Review URL: http://codereview.chromium.org/3156028 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5309 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/builtins-arm.cc | 3 +-- src/arm/codegen-arm.cc | 6 +++-- src/arm/macro-assembler-arm.cc | 33 ++++++++++--------------- src/arm/macro-assembler-arm.h | 3 +++ src/ia32/builtins-ia32.cc | 3 +-- src/ia32/codegen-ia32.cc | 7 ++++-- src/ia32/macro-assembler-ia32.cc | 41 +++++++++++++------------------- src/ia32/macro-assembler-ia32.h | 3 +++ src/liveedit.cc | 18 +++++++++++--- src/mark-compact.cc | 41 +++++++++++++++++++++++++------- src/objects-inl.h | 17 +++++++++---- src/objects.cc | 25 +++++++++++++++++-- src/objects.h | 14 +++++++++-- src/serialize.cc | 29 +++++++++++++++++++++- src/serialize.h | 1 + src/x64/builtins-x64.cc | 3 +-- src/x64/codegen-x64.cc | 7 ++++-- src/x64/macro-assembler-x64.cc | 30 +++++++++-------------- src/x64/macro-assembler-x64.h | 3 +++ 19 files changed, 190 insertions(+), 97 deletions(-) diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc index 7e7e358c10..224b75f1e0 100644 --- a/src/arm/builtins-arm.cc +++ b/src/arm/builtins-arm.cc @@ -1073,8 +1073,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ ldr(r2, FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset)); __ mov(r2, Operand(r2, ASR, kSmiTagSize)); - __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeOffset)); - __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); + __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); __ cmp(r2, r0); // Check formal and actual parameter counts. __ Jump(Handle(builtin(ArgumentsAdaptorTrampoline)), RelocInfo::CODE_TARGET, ne); diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index 15f34b5944..675c5867b8 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -1556,7 +1556,8 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE); __ b(ne, &build_args); Handle apply_code(Builtins::builtin(Builtins::FunctionApply)); - __ ldr(r1, FieldMemOperand(r0, JSFunction::kCodeOffset)); + __ ldr(r1, FieldMemOperand(r0, JSFunction::kCodeEntryOffset)); + __ sub(r1, r1, Operand(Code::kHeaderSize - kHeapObjectTag)); __ cmp(r1, Operand(apply_code)); __ b(ne, &build_args); @@ -7028,7 +7029,8 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) { // Initialize the code pointer in the function to be the one // found in the shared function info object. __ ldr(r3, FieldMemOperand(r3, SharedFunctionInfo::kCodeOffset)); - __ str(r3, FieldMemOperand(r0, JSFunction::kCodeOffset)); + __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); + __ str(r3, FieldMemOperand(r0, JSFunction::kCodeEntryOffset)); // Return result. The argument function info has been popped already. __ Ret(); diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index 2058ee2881..0d04156d23 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -757,8 +757,7 @@ void MacroAssembler::InvokeFunction(Register fun, SharedFunctionInfo::kFormalParameterCountOffset)); mov(expected_reg, Operand(expected_reg, ASR, kSmiTagSize)); ldr(code_reg, - MemOperand(r1, JSFunction::kCodeOffset - kHeapObjectTag)); - add(code_reg, code_reg, Operand(Code::kHeaderSize - kHeapObjectTag)); + FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); ParameterCount expected(expected_reg); InvokeCode(code_reg, expected, actual, flag); @@ -1490,30 +1489,22 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, } -void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { - ASSERT(!target.is(r1)); - +void MacroAssembler::GetBuiltinFunction(Register target, + Builtins::JavaScript id) { // Load the builtins object into target register. ldr(target, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); ldr(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset)); - // Load the JavaScript builtin function from the builtins object. - ldr(r1, FieldMemOperand(target, - JSBuiltinsObject::OffsetOfFunctionWithId(id))); - - // Load the code entry point from the builtins object. ldr(target, FieldMemOperand(target, - JSBuiltinsObject::OffsetOfCodeWithId(id))); - if (FLAG_debug_code) { - // Make sure the code objects in the builtins object and in the - // builtin function are the same. - push(r1); - ldr(r1, FieldMemOperand(r1, JSFunction::kCodeOffset)); - cmp(r1, target); - Assert(eq, "Builtin code object changed"); - pop(r1); - } - add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag)); + JSBuiltinsObject::OffsetOfFunctionWithId(id))); +} + + +void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { + ASSERT(!target.is(r1)); + GetBuiltinFunction(r1, id); + // Load the code entry point from the builtins object. + ldr(target, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); } diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 7843f006e6..a1c5dbb555 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -576,6 +576,9 @@ class MacroAssembler: public Assembler { // setup the function in r1. void GetBuiltinEntry(Register target, Builtins::JavaScript id); + // Store the function for the given builtin in the target register. + void GetBuiltinFunction(Register target, Builtins::JavaScript id); + Handle CodeObject() { return code_object_; } diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index 35a90a4aca..15c3198f82 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -567,9 +567,8 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); __ mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); + __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); __ SmiUntag(ebx); - __ mov(edx, FieldOperand(edi, JSFunction::kCodeOffset)); - __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); __ cmp(eax, Operand(ebx)); __ j(not_equal, Handle(builtin(ArgumentsAdaptorTrampoline))); diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 02a03fc733..78d83ddfd8 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -3423,8 +3423,10 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, __ j(zero, &build_args); __ CmpObjectType(eax, JS_FUNCTION_TYPE, ecx); __ j(not_equal, &build_args); + __ mov(ecx, FieldOperand(eax, JSFunction::kCodeEntryOffset)); + __ sub(Operand(ecx), Immediate(Code::kHeaderSize - kHeapObjectTag)); Handle apply_code(Builtins::builtin(Builtins::FunctionApply)); - __ cmp(FieldOperand(eax, JSFunction::kCodeOffset), Immediate(apply_code)); + __ cmp(Operand(ecx), Immediate(apply_code)); __ j(not_equal, &build_args); // Check that applicand is a function. @@ -9815,7 +9817,8 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) { // Initialize the code pointer in the function to be the one // found in the shared function info object. __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); - __ mov(FieldOperand(eax, JSFunction::kCodeOffset), edx); + __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); + __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx); // Return and remove the on-stack parameter. __ ret(1 * kPointerSize); diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc index 658caf1ef8..79b40641b2 100644 --- a/src/ia32/macro-assembler-ia32.cc +++ b/src/ia32/macro-assembler-ia32.cc @@ -1298,11 +1298,10 @@ void MacroAssembler::InvokeFunction(Register fun, mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); mov(ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); SmiUntag(ebx); - mov(edx, FieldOperand(edi, JSFunction::kCodeOffset)); - lea(edx, FieldOperand(edx, Code::kHeaderSize)); ParameterCount expected(ebx); - InvokeCode(Operand(edx), expected, actual, flag); + InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), + expected, actual, flag); } @@ -1313,7 +1312,6 @@ void MacroAssembler::InvokeFunction(JSFunction* function, // Get the function and setup the context. mov(edi, Immediate(Handle(function))); mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); - // Invoke the cached code. Handle code(function->code()); ParameterCount expected(function->shared()->formal_parameter_count()); @@ -1329,33 +1327,26 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) { // arguments match the expected number of arguments. Fake a // parameter count to avoid emitting code to do the check. ParameterCount expected(0); - GetBuiltinEntry(edx, id); - InvokeCode(Operand(edx), expected, expected, flag); + GetBuiltinFunction(edi, id); + InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), + expected, expected, flag); } +void MacroAssembler::GetBuiltinFunction(Register target, + Builtins::JavaScript id) { + // Load the JavaScript builtin function from the builtins object. + mov(target, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); + mov(target, FieldOperand(target, GlobalObject::kBuiltinsOffset)); + mov(target, FieldOperand(target, + JSBuiltinsObject::OffsetOfFunctionWithId(id))); +} void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { ASSERT(!target.is(edi)); - - // Load the builtins object into target register. - mov(target, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); - mov(target, FieldOperand(target, GlobalObject::kBuiltinsOffset)); - // Load the JavaScript builtin function from the builtins object. - mov(edi, FieldOperand(target, JSBuiltinsObject::OffsetOfFunctionWithId(id))); - - // Load the code entry point from the builtins object. - mov(target, FieldOperand(target, JSBuiltinsObject::OffsetOfCodeWithId(id))); - if (FLAG_debug_code) { - // Make sure the code objects in the builtins object and in the - // builtin function are the same. - push(target); - mov(target, FieldOperand(edi, JSFunction::kCodeOffset)); - cmp(target, Operand(esp, 0)); - Assert(equal, "Builtin code object changed"); - pop(target); - } - lea(target, FieldOperand(target, Code::kHeaderSize)); + GetBuiltinFunction(edi, id); + // Load the code entry point from the function into the target register. + mov(target, FieldOperand(edi, JSFunction::kCodeEntryOffset)); } diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index c23f6873a1..e5abfb4686 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -169,6 +169,9 @@ class MacroAssembler: public Assembler { // the unresolved list if the name does not resolve. void InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag); + // Store the function for the given builtin in the target register. + void GetBuiltinFunction(Register target, Builtins::JavaScript id); + // Store the code object for the given builtin in the target register. void GetBuiltinEntry(Register target, Builtins::JavaScript id); diff --git a/src/liveedit.cc b/src/liveedit.cc index 769ac35c85..5f7e583c20 100644 --- a/src/liveedit.cc +++ b/src/liveedit.cc @@ -750,7 +750,7 @@ void LiveEdit::WrapSharedFunctionInfos(Handle array) { class ReferenceCollectorVisitor : public ObjectVisitor { public: explicit ReferenceCollectorVisitor(Code* original) - : original_(original), rvalues_(10), reloc_infos_(10) { + : original_(original), rvalues_(10), reloc_infos_(10), code_entries_(10) { } virtual void VisitPointers(Object** start, Object** end) { @@ -761,7 +761,13 @@ class ReferenceCollectorVisitor : public ObjectVisitor { } } - void VisitCodeTarget(RelocInfo* rinfo) { + virtual void VisitCodeEntry(Address entry) { + if (Code::GetObjectFromEntryAddress(entry) == original_) { + code_entries_.Add(entry); + } + } + + virtual void VisitCodeTarget(RelocInfo* rinfo) { if (RelocInfo::IsCodeTarget(rinfo->rmode()) && Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) { reloc_infos_.Add(*rinfo); @@ -778,8 +784,13 @@ class ReferenceCollectorVisitor : public ObjectVisitor { for (int i = 0; i < rvalues_.length(); i++) { *(rvalues_[i]) = substitution; } + Address substitution_entry = substitution->instruction_start(); for (int i = 0; i < reloc_infos_.length(); i++) { - reloc_infos_[i].set_target_address(substitution->instruction_start()); + reloc_infos_[i].set_target_address(substitution_entry); + } + for (int i = 0; i < code_entries_.length(); i++) { + Address entry = code_entries_[i]; + Memory::Address_at(entry) = substitution_entry; } } @@ -787,6 +798,7 @@ class ReferenceCollectorVisitor : public ObjectVisitor { Code* original_; ZoneList rvalues_; ZoneList reloc_infos_; + ZoneList
code_entries_; }; diff --git a/src/mark-compact.cc b/src/mark-compact.cc index c5eabebbcb..e7a26194e9 100644 --- a/src/mark-compact.cc +++ b/src/mark-compact.cc @@ -255,10 +255,9 @@ class StaticMarkingVisitor : public StaticVisitorBase { static void EnableCodeFlushing(bool enabled) { if (enabled) { - table_.Register(kVisitJSFunction, &VisitJSFunction); + table_.Register(kVisitJSFunction, &VisitJSFunctionAndFlushCode); } else { - table_.Register(kVisitJSFunction, - &JSObjectVisitor::VisitSpecialized); + table_.Register(kVisitJSFunction, &VisitJSFunction); } } @@ -299,7 +298,7 @@ class StaticMarkingVisitor : public StaticVisitorBase { table_.Register(kVisitCode, &VisitCode); - table_.Register(kVisitJSFunction, &VisitJSFunction); + table_.Register(kVisitJSFunction, &VisitJSFunctionAndFlushCode); table_.Register(kVisitPropertyCell, &FixedBodyVisitor(object); + static void VisitCodeEntry(Address entry_address) { + Object* code = Code::GetObjectFromEntryAddress(entry_address); + Object* old_code = code; + VisitPointer(&code); + if (code != old_code) { + Memory::Address_at(entry_address) = + reinterpret_cast(code)->entry(); + } + } + + static void VisitJSFunctionAndFlushCode(Map* map, HeapObject* object) { + JSFunction* jsfunction = reinterpret_cast(object); // The function must have a valid context and not be a builtin. if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) { FlushCodeForFunction(jsfunction); } - - JSObjectVisitor::VisitSpecialized(map, object); + VisitJSFunction(map, object); } + + static void VisitJSFunction(Map* map, HeapObject* object) { +#define SLOT_ADDR(obj, offset) \ + reinterpret_cast((obj)->address() + offset) + + VisitPointers(SLOT_ADDR(object, JSFunction::kPropertiesOffset), + SLOT_ADDR(object, JSFunction::kCodeEntryOffset)); + + VisitCodeEntry(object->address() + JSFunction::kCodeEntryOffset); + + VisitPointers(SLOT_ADDR(object, + JSFunction::kCodeEntryOffset + kPointerSize), + SLOT_ADDR(object, JSFunction::kSize)); +#undef SLOT_ADDR + } + + typedef void (*Callback)(Map* map, HeapObject* object); static VisitorDispatchTable table_; diff --git a/src/objects-inl.h b/src/objects-inl.h index 7bd4514ed0..0ef39fcd70 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -35,9 +35,10 @@ #ifndef V8_OBJECTS_INL_H_ #define V8_OBJECTS_INL_H_ -#include "objects.h" +#include "memory.h" #include "contexts.h" #include "conversions-inl.h" +#include "objects.h" #include "property.h" namespace v8 { @@ -2410,6 +2411,12 @@ Code* Code::GetCodeFromTargetAddress(Address address) { } +Object* Code::GetObjectFromEntryAddress(Address location_of_address) { + return HeapObject:: + FromAddress(Memory::Address_at(location_of_address) - Code::kHeaderSize); +} + + Object* Map::prototype() { return READ_FIELD(this, kPrototypeOffset); } @@ -2739,19 +2746,21 @@ bool JSFunction::IsBuiltin() { Code* JSFunction::code() { - return Code::cast(READ_FIELD(this, kCodeOffset)); + return Code::cast(unchecked_code()); } Code* JSFunction::unchecked_code() { - return reinterpret_cast(READ_FIELD(this, kCodeOffset)); + return reinterpret_cast( + Code::GetObjectFromEntryAddress(FIELD_ADDR(this, kCodeEntryOffset))); } void JSFunction::set_code(Code* value) { // Skip the write barrier because code is never in new space. ASSERT(!Heap::InNewSpace(value)); - WRITE_FIELD(this, kCodeOffset, value); + Address entry = value->entry(); + WRITE_INTPTR_FIELD(this, kCodeEntryOffset, reinterpret_cast(entry)); } diff --git a/src/objects.cc b/src/objects.cc index 3495eab822..1a4ed0559c 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1066,12 +1066,15 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case JS_VALUE_TYPE: case JS_ARRAY_TYPE: case JS_REGEXP_TYPE: - case JS_FUNCTION_TYPE: case JS_GLOBAL_PROXY_TYPE: case JS_GLOBAL_OBJECT_TYPE: case JS_BUILTINS_OBJECT_TYPE: JSObject::BodyDescriptor::IterateBody(this, object_size, v); break; + case JS_FUNCTION_TYPE: + reinterpret_cast(this) + ->JSFunctionIterateBody(object_size, v); + break; case ODDBALL_TYPE: Oddball::BodyDescriptor::IterateBody(this, v); break; @@ -4988,6 +4991,15 @@ void Map::ClearNonLiveTransitions(Object* real_prototype) { } +void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { + // Iterate over all fields in the body but take care in dealing with + // the code entry. + IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); + v->VisitCodeEntry(this->address() + kCodeEntryOffset); + IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); +} + + Object* JSFunction::SetInstancePrototype(Object* value) { ASSERT(value->IsJSObject()); @@ -5004,7 +5016,6 @@ Object* JSFunction::SetInstancePrototype(Object* value) { } - Object* JSFunction::SetPrototype(Object* value) { ASSERT(should_have_prototype()); Object* construct_prototype = value; @@ -5232,6 +5243,16 @@ void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { } +void ObjectVisitor::VisitCodeEntry(Address entry_address) { + Object* code = Code::GetObjectFromEntryAddress(entry_address); + Object* old_code = code; + VisitPointer(&code); + if (code != old_code) { + Memory::Address_at(entry_address) = reinterpret_cast(code)->entry(); + } +} + + void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) { ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) && rinfo->IsPatchedReturnSequence()) || diff --git a/src/objects.h b/src/objects.h index be3055b2cf..b23920caa6 100644 --- a/src/objects.h +++ b/src/objects.h @@ -2883,6 +2883,9 @@ class Code: public HeapObject { // Convert a target address into a code object. static inline Code* GetCodeFromTargetAddress(Address address); + // Convert an entry address into an object. + static inline Object* GetObjectFromEntryAddress(Address location_of_address); + // Returns the address of the first instruction. inline byte* instruction_start(); @@ -3705,6 +3708,10 @@ class JSFunction: public JSObject { // Casting. static inline JSFunction* cast(Object* obj); + // Iterates the objects, including code objects indirectly referenced + // through pointers to the first instruction in the code object. + void JSFunctionIterateBody(int object_size, ObjectVisitor* v); + // Dispatched behavior. #ifdef DEBUG void JSFunctionPrint(); @@ -3718,9 +3725,9 @@ class JSFunction: public JSObject { static Context* GlobalContextFromLiterals(FixedArray* literals); // Layout descriptors. - static const int kCodeOffset = JSObject::kHeaderSize; + static const int kCodeEntryOffset = JSObject::kHeaderSize; static const int kPrototypeOrInitialMapOffset = - kCodeOffset + kPointerSize; + kCodeEntryOffset + kPointerSize; static const int kSharedFunctionInfoOffset = kPrototypeOrInitialMapOffset + kPointerSize; static const int kContextOffset = kSharedFunctionInfoOffset + kPointerSize; @@ -5435,6 +5442,9 @@ class ObjectVisitor BASE_EMBEDDED { // Visits a code target in the instruction stream. virtual void VisitCodeTarget(RelocInfo* rinfo); + // Visits a code entry in a JS function. + virtual void VisitCodeEntry(Address entry_address); + // Visits a runtime entry in the instruction stream. virtual void VisitRuntimeEntry(RelocInfo* rinfo) {} diff --git a/src/serialize.cc b/src/serialize.cc index 0057d18f1d..cdde07e3d4 100644 --- a/src/serialize.cc +++ b/src/serialize.cc @@ -831,6 +831,12 @@ void Deserializer::ReadChunk(Object** current, CASE_STATEMENT(where, how, within, kLargeFixedArray) \ CASE_BODY(where, how, within, kAnyOldSpace, kUnknownOffsetFromStart) +#define ONE_PER_CODE_SPACE(where, how, within) \ + CASE_STATEMENT(where, how, within, CODE_SPACE) \ + CASE_BODY(where, how, within, CODE_SPACE, kUnknownOffsetFromStart) \ + CASE_STATEMENT(where, how, within, kLargeCode) \ + CASE_BODY(where, how, within, LO_SPACE, kUnknownOffsetFromStart) + #define EMIT_COMMON_REFERENCE_PATTERNS(pseudo_space_number, \ space_number, \ offset_from_start) \ @@ -862,6 +868,8 @@ void Deserializer::ReadChunk(Object** current, // Deserialize a new object and write a pointer to it to the current // object. ONE_PER_SPACE(kNewObject, kPlain, kStartOfObject) + // Support for direct instruction pointers in functions + ONE_PER_CODE_SPACE(kNewObject, kPlain, kFirstInstruction) // Deserialize a new code object and write a pointer to its first // instruction to the current code object. ONE_PER_SPACE(kNewObject, kFromCode, kFirstInstruction) @@ -870,11 +878,14 @@ void Deserializer::ReadChunk(Object** current, ALL_SPACES(kBackref, kPlain, kStartOfObject) // Find a recently deserialized code object using its offset from the // current allocation point and write a pointer to its first instruction - // to the current code object. + // to the current code object or the instruction pointer in a function + // object. ALL_SPACES(kBackref, kFromCode, kFirstInstruction) + ALL_SPACES(kBackref, kPlain, kFirstInstruction) // Find an already deserialized object using its offset from the start // and write a pointer to it to the current object. ALL_SPACES(kFromStart, kPlain, kStartOfObject) + ALL_SPACES(kFromStart, kPlain, kFirstInstruction) // Find an already deserialized code object using its offset from the // start and write a pointer to its first instruction to the current code // object. @@ -894,6 +905,14 @@ void Deserializer::ReadChunk(Object** current, kStartOfObject, 0, kUnknownOffsetFromStart) + // Find an code entry in the partial snapshots cache and + // write a pointer to it to the current object. + CASE_STATEMENT(kPartialSnapshotCache, kPlain, kFirstInstruction, 0) + CASE_BODY(kPartialSnapshotCache, + kPlain, + kFirstInstruction, + 0, + kUnknownOffsetFromStart) // Find an external reference and write a pointer to it to the current // object. CASE_STATEMENT(kExternalReference, kPlain, kStartOfObject, 0) @@ -1336,6 +1355,14 @@ void Serializer::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) { } +void Serializer::ObjectSerializer::VisitCodeEntry(Address entry_address) { + Code* target = Code::cast(Code::GetObjectFromEntryAddress(entry_address)); + OutputRawData(entry_address); + serializer_->SerializeObject(target, kPlain, kFirstInstruction); + bytes_processed_so_far_ += kPointerSize; +} + + void Serializer::ObjectSerializer::VisitExternalAsciiString( v8::String::ExternalAsciiStringResource** resource_pointer) { Address references_start = reinterpret_cast
(resource_pointer); diff --git a/src/serialize.h b/src/serialize.h index 80be50da5e..92a514975c 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -448,6 +448,7 @@ class Serializer : public SerializerDeserializer { void VisitPointers(Object** start, Object** end); void VisitExternalReferences(Address* start, Address* end); void VisitCodeTarget(RelocInfo* target); + void VisitCodeEntry(Address entry_address); void VisitRuntimeEntry(RelocInfo* reloc); // Used for seralizing the external strings that hold the natives source. void VisitExternalAsciiString( diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc index 4f2d2b9616..7cc493e545 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -310,8 +310,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ movsxlq(rbx, FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset)); - __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeOffset)); - __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize)); + __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); __ cmpq(rax, rbx); __ j(not_equal, Handle(builtin(ArgumentsAdaptorTrampoline)), diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 1885182287..9f075af112 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -2616,8 +2616,10 @@ void CodeGenerator::CallApplyLazy(Expression* applicand, __ j(is_smi, &build_args); __ CmpObjectType(rax, JS_FUNCTION_TYPE, rcx); __ j(not_equal, &build_args); + __ movq(rcx, FieldOperand(rax, JSFunction::kCodeEntryOffset)); + __ subq(rcx, Immediate(Code::kHeaderSize - kHeapObjectTag)); Handle apply_code(Builtins::builtin(Builtins::FunctionApply)); - __ Cmp(FieldOperand(rax, JSFunction::kCodeOffset), apply_code); + __ Cmp(FieldOperand(rcx, SharedFunctionInfo::kCodeOffset), apply_code); __ j(not_equal, &build_args); // Check that applicand is a function. @@ -8758,7 +8760,8 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) { // Initialize the code pointer in the function to be the one // found in the shared function info object. __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset)); - __ movq(FieldOperand(rax, JSFunction::kCodeOffset), rdx); + __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize)); + __ movq(FieldOperand(rax, JSFunction::kCodeEntryOffset), rdx); // Return and remove the on-stack parameter. diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 2f4b5f6ad2..a6837bbea6 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -581,28 +581,21 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) { } -void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { - ASSERT(!target.is(rdi)); - +void MacroAssembler::GetBuiltinFunction(Register target, + Builtins::JavaScript id) { // Load the builtins object into target register. movq(target, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); movq(target, FieldOperand(target, GlobalObject::kBuiltinsOffset)); + movq(target, FieldOperand(target, + JSBuiltinsObject::OffsetOfFunctionWithId(id))); +} + +void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { + ASSERT(!target.is(rdi)); // Load the JavaScript builtin function from the builtins object. - movq(rdi, FieldOperand(target, JSBuiltinsObject::OffsetOfFunctionWithId(id))); - - // Load the code entry point from the builtins object. - movq(target, FieldOperand(target, JSBuiltinsObject::OffsetOfCodeWithId(id))); - if (FLAG_debug_code) { - // Make sure the code objects in the builtins object and in the - // builtin function are the same. - push(target); - movq(target, FieldOperand(rdi, JSFunction::kCodeOffset)); - cmpq(target, Operand(rsp, 0)); - Assert(equal, "Builtin code object changed"); - pop(target); - } - lea(target, FieldOperand(target, Code::kHeaderSize)); + GetBuiltinFunction(rdi, id); + movq(target, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); } @@ -2311,10 +2304,9 @@ void MacroAssembler::InvokeFunction(Register function, movq(rsi, FieldOperand(function, JSFunction::kContextOffset)); movsxlq(rbx, FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset)); - movq(rdx, FieldOperand(rdi, JSFunction::kCodeOffset)); // Advances rdx to the end of the Code object header, to the start of // the executable code. - lea(rdx, FieldOperand(rdx, Code::kHeaderSize)); + movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); ParameterCount expected(rbx); InvokeCode(rdx, expected, actual, flag); diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index aedc3b9ced..08cb377370 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -203,6 +203,9 @@ class MacroAssembler: public Assembler { // the unresolved list if the name does not resolve. void InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag); + // Store the function for the given builtin in the target register. + void GetBuiltinFunction(Register target, Builtins::JavaScript id); + // Store the code object for the given builtin in the target register. void GetBuiltinEntry(Register target, Builtins::JavaScript id);