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
This commit is contained in:
parent
103d7c7993
commit
2982f5e320
@ -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<Code>(builtin(ArgumentsAdaptorTrampoline)),
|
||||
RelocInfo::CODE_TARGET, ne);
|
||||
|
@ -1556,7 +1556,8 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
|
||||
__ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE);
|
||||
__ b(ne, &build_args);
|
||||
Handle<Code> 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();
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<Object> CodeObject() { return code_object_; }
|
||||
|
||||
|
||||
|
@ -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<Code>(builtin(ArgumentsAdaptorTrampoline)));
|
||||
|
||||
|
@ -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<Code> 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);
|
||||
|
@ -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<JSFunction>(function)));
|
||||
mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
|
||||
|
||||
// Invoke the cached code.
|
||||
Handle<Code> 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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -750,7 +750,7 @@ void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> 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<Object**> rvalues_;
|
||||
ZoneList<RelocInfo> reloc_infos_;
|
||||
ZoneList<Address> code_entries_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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<JSFunction::kSize>);
|
||||
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<StaticMarkingVisitor,
|
||||
@ -534,17 +533,43 @@ class StaticMarkingVisitor : public StaticVisitorBase {
|
||||
}
|
||||
|
||||
|
||||
static void VisitJSFunction(Map* map, HeapObject* object) {
|
||||
JSFunction* jsfunction = reinterpret_cast<JSFunction*>(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*>(code)->entry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void VisitJSFunctionAndFlushCode(Map* map, HeapObject* object) {
|
||||
JSFunction* jsfunction = reinterpret_cast<JSFunction*>(object);
|
||||
// The function must have a valid context and not be a builtin.
|
||||
if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) {
|
||||
FlushCodeForFunction(jsfunction);
|
||||
}
|
||||
|
||||
JSObjectVisitor::VisitSpecialized<JSFunction::kSize>(map, object);
|
||||
VisitJSFunction(map, object);
|
||||
}
|
||||
|
||||
|
||||
static void VisitJSFunction(Map* map, HeapObject* object) {
|
||||
#define SLOT_ADDR(obj, offset) \
|
||||
reinterpret_cast<Object**>((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<Callback> table_;
|
||||
|
@ -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<Code*>(READ_FIELD(this, kCodeOffset));
|
||||
return reinterpret_cast<Code*>(
|
||||
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<intptr_t>(entry));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<JSFunction*>(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*>(code)->entry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
|
||||
ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
|
||||
rinfo->IsPatchedReturnSequence()) ||
|
||||
|
@ -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) {}
|
||||
|
||||
|
@ -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<Address>(resource_pointer);
|
||||
|
@ -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(
|
||||
|
@ -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<Code>(builtin(ArgumentsAdaptorTrampoline)),
|
||||
|
@ -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<Code> 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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user