Always load the JavaScript builtins code entry from the JavaScript
function instead of baking in the address of the first one that we see in code. This removes the need for fixups processing and makes the stubs safe when there is no natives cache and therefore multiple versions of the builtin functions. Review URL: http://codereview.chromium.org/594009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3832 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
4f7b9e4da3
commit
638cb4f91d
@ -37,7 +37,6 @@ namespace internal {
|
||||
|
||||
MacroAssembler::MacroAssembler(void* buffer, int size)
|
||||
: Assembler(buffer, size),
|
||||
unresolved_(0),
|
||||
generating_stub_(false),
|
||||
allow_stub_calls_(true),
|
||||
code_object_(Heap::undefined_value()) {
|
||||
@ -1233,58 +1232,28 @@ void MacroAssembler::JumpToRuntime(const ExternalReference& builtin) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
|
||||
bool* resolved) {
|
||||
// Contract with compiled functions is that the function is passed in r1.
|
||||
int builtins_offset =
|
||||
JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
|
||||
ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||
ldr(r1, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
|
||||
ldr(r1, FieldMemOperand(r1, builtins_offset));
|
||||
|
||||
return Builtins::GetCode(id, resolved);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
|
||||
InvokeJSFlags flags) {
|
||||
bool resolved;
|
||||
Handle<Code> code = ResolveBuiltin(id, &resolved);
|
||||
|
||||
GetBuiltinEntry(r2, id);
|
||||
if (flags == CALL_JS) {
|
||||
Call(code, RelocInfo::CODE_TARGET);
|
||||
Call(r2);
|
||||
} else {
|
||||
ASSERT(flags == JUMP_JS);
|
||||
Jump(code, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
if (!resolved) {
|
||||
const char* name = Builtins::GetName(id);
|
||||
int argc = Builtins::GetArgumentsCount(id);
|
||||
uint32_t flags =
|
||||
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
|
||||
Bootstrapper::FixupFlagsUseCodeObject::encode(false);
|
||||
Unresolved entry = { pc_offset() - kInstrSize, flags, name };
|
||||
unresolved_.Add(entry);
|
||||
Jump(r2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
|
||||
bool resolved;
|
||||
Handle<Code> code = ResolveBuiltin(id, &resolved);
|
||||
|
||||
mov(target, Operand(code));
|
||||
if (!resolved) {
|
||||
const char* name = Builtins::GetName(id);
|
||||
int argc = Builtins::GetArgumentsCount(id);
|
||||
uint32_t flags =
|
||||
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
|
||||
Bootstrapper::FixupFlagsUseCodeObject::encode(true);
|
||||
Unresolved entry = { pc_offset() - kInstrSize, flags, name };
|
||||
unresolved_.Add(entry);
|
||||
}
|
||||
|
||||
// Load the JavaScript builtin function from the builtins object.
|
||||
ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||
ldr(r1, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
|
||||
int builtins_offset =
|
||||
JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
|
||||
ldr(r1, FieldMemOperand(r1, builtins_offset));
|
||||
// Load the code entry point from the function into the target register.
|
||||
ldr(target, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
||||
ldr(target, FieldMemOperand(target, SharedFunctionInfo::kCodeOffset));
|
||||
add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
}
|
||||
|
||||
|
@ -353,13 +353,6 @@ class MacroAssembler: public Assembler {
|
||||
// setup the function in r1.
|
||||
void GetBuiltinEntry(Register target, Builtins::JavaScript id);
|
||||
|
||||
struct Unresolved {
|
||||
int pc;
|
||||
uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders.
|
||||
const char* name;
|
||||
};
|
||||
List<Unresolved>* unresolved() { return &unresolved_; }
|
||||
|
||||
Handle<Object> CodeObject() { return code_object_; }
|
||||
|
||||
|
||||
@ -432,23 +425,10 @@ class MacroAssembler: public Assembler {
|
||||
Label* done,
|
||||
InvokeFlag flag);
|
||||
|
||||
// Prepares for a call or jump to a builtin by doing two things:
|
||||
// 1. Emits code that fetches the builtin's function object from the context
|
||||
// at runtime, and puts it in the register rdi.
|
||||
// 2. Fetches the builtin's code object, and returns it in a handle, at
|
||||
// compile time, so that later code can emit instructions to jump or call
|
||||
// the builtin directly. If the code object has not yet been created, it
|
||||
// returns the builtin code object for IllegalFunction, and sets the
|
||||
// output parameter "resolved" to false. Code that uses the return value
|
||||
// should then add the address and the builtin name to the list of fixups
|
||||
// called unresolved_, which is fixed up by the bootstrapper.
|
||||
Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
|
||||
|
||||
// Activation support.
|
||||
void EnterFrame(StackFrame::Type type);
|
||||
void LeaveFrame(StackFrame::Type type);
|
||||
|
||||
List<Unresolved> unresolved_;
|
||||
bool generating_stub_;
|
||||
bool allow_stub_calls_;
|
||||
// This handle will be patched with the code object on installation.
|
||||
|
@ -192,116 +192,6 @@ void Bootstrapper::TearDown() {
|
||||
}
|
||||
|
||||
|
||||
// Pending fixups are code positions that refer to builtin code
|
||||
// objects that were not available at the time the code was generated.
|
||||
// The pending list is processed whenever an environment has been
|
||||
// created.
|
||||
class PendingFixups : public AllStatic {
|
||||
public:
|
||||
static void Add(Code* code, MacroAssembler* masm);
|
||||
static bool Process(Handle<JSBuiltinsObject> builtins);
|
||||
|
||||
static void Iterate(ObjectVisitor* v);
|
||||
|
||||
private:
|
||||
static List<Object*> code_;
|
||||
static List<const char*> name_;
|
||||
static List<int> pc_;
|
||||
static List<uint32_t> flags_;
|
||||
|
||||
static void Clear();
|
||||
};
|
||||
|
||||
|
||||
List<Object*> PendingFixups::code_(0);
|
||||
List<const char*> PendingFixups::name_(0);
|
||||
List<int> PendingFixups::pc_(0);
|
||||
List<uint32_t> PendingFixups::flags_(0);
|
||||
|
||||
|
||||
void PendingFixups::Add(Code* code, MacroAssembler* masm) {
|
||||
// Note this code is not only called during bootstrapping.
|
||||
List<MacroAssembler::Unresolved>* unresolved = masm->unresolved();
|
||||
int n = unresolved->length();
|
||||
for (int i = 0; i < n; i++) {
|
||||
const char* name = unresolved->at(i).name;
|
||||
code_.Add(code);
|
||||
name_.Add(name);
|
||||
pc_.Add(unresolved->at(i).pc);
|
||||
flags_.Add(unresolved->at(i).flags);
|
||||
LOG(StringEvent("unresolved", name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PendingFixups::Process(Handle<JSBuiltinsObject> builtins) {
|
||||
HandleScope scope;
|
||||
// NOTE: Extra fixups may be added to the list during the iteration
|
||||
// due to lazy compilation of functions during the processing. Do not
|
||||
// cache the result of getting the length of the code list.
|
||||
for (int i = 0; i < code_.length(); i++) {
|
||||
const char* name = name_[i];
|
||||
uint32_t flags = flags_[i];
|
||||
Handle<String> symbol = Factory::LookupAsciiSymbol(name);
|
||||
Object* o = builtins->GetProperty(*symbol);
|
||||
#ifdef DEBUG
|
||||
if (!o->IsJSFunction()) {
|
||||
V8_Fatal(__FILE__, __LINE__, "Cannot resolve call to builtin %s", name);
|
||||
}
|
||||
#endif
|
||||
Handle<SharedFunctionInfo> shared(JSFunction::cast(o)->shared());
|
||||
// Make sure the number of parameters match the formal parameter count.
|
||||
int argc = Bootstrapper::FixupFlagsArgumentsCount::decode(flags);
|
||||
USE(argc);
|
||||
ASSERT(shared->formal_parameter_count() == argc);
|
||||
// Do lazy compilation if necessary and check for stack overflows.
|
||||
if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) {
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
Code* code = Code::cast(code_[i]);
|
||||
Address pc = code->instruction_start() + pc_[i];
|
||||
RelocInfo target(pc, RelocInfo::CODE_TARGET, 0);
|
||||
bool use_code_object = Bootstrapper::FixupFlagsUseCodeObject::decode(flags);
|
||||
if (use_code_object) {
|
||||
target.set_target_object(shared->code());
|
||||
} else {
|
||||
target.set_target_address(shared->code()->instruction_start());
|
||||
}
|
||||
LOG(StringEvent("resolved", name));
|
||||
}
|
||||
Clear();
|
||||
|
||||
// TODO(1240818): We should probably try to avoid doing this for all
|
||||
// the V8 builtin JS files. It should only happen after running
|
||||
// runtime.js - just like there shouldn't be any fixups left after
|
||||
// that.
|
||||
for (int i = 0; i < Builtins::NumberOfJavaScriptBuiltins(); i++) {
|
||||
Builtins::JavaScript id = static_cast<Builtins::JavaScript>(i);
|
||||
Handle<String> name = Factory::LookupAsciiSymbol(Builtins::GetName(id));
|
||||
JSFunction* function = JSFunction::cast(builtins->GetProperty(*name));
|
||||
builtins->set_javascript_builtin(id, function);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PendingFixups::Clear() {
|
||||
code_.Clear();
|
||||
name_.Clear();
|
||||
pc_.Clear();
|
||||
flags_.Clear();
|
||||
}
|
||||
|
||||
|
||||
void PendingFixups::Iterate(ObjectVisitor* v) {
|
||||
if (!code_.is_empty()) {
|
||||
v->VisitPointers(&code_[0], &code_[0] + code_.length());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Genesis BASE_EMBEDDED {
|
||||
public:
|
||||
Genesis(Handle<Object> global_object,
|
||||
@ -338,6 +228,7 @@ class Genesis BASE_EMBEDDED {
|
||||
bool InstallExtension(const char* name);
|
||||
bool InstallExtension(v8::RegisteredExtension* current);
|
||||
bool InstallSpecialObjects();
|
||||
bool InstallJSBuiltins(Handle<JSBuiltinsObject> builtins);
|
||||
bool ConfigureApiObject(Handle<JSObject> object,
|
||||
Handle<ObjectTemplateInfo> object_template);
|
||||
bool ConfigureGlobalObjects(v8::Handle<v8::ObjectTemplate> global_template);
|
||||
@ -379,15 +270,6 @@ void Bootstrapper::Iterate(ObjectVisitor* v) {
|
||||
v->Synchronize("NativesCache");
|
||||
extensions_cache.Iterate(v);
|
||||
v->Synchronize("Extensions");
|
||||
PendingFixups::Iterate(v);
|
||||
v->Synchronize("PendingFixups");
|
||||
}
|
||||
|
||||
|
||||
// While setting up the environment, we collect code positions that
|
||||
// need to be patched before we can run any code in the environment.
|
||||
void Bootstrapper::AddFixup(Code* code, MacroAssembler* masm) {
|
||||
PendingFixups::Add(code, masm);
|
||||
}
|
||||
|
||||
|
||||
@ -968,8 +850,7 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
|
||||
Handle<Object> result =
|
||||
Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
|
||||
if (has_pending_exception) return false;
|
||||
return PendingFixups::Process(
|
||||
Handle<JSBuiltinsObject>(Top::context()->builtins()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -1176,6 +1057,10 @@ bool Genesis::InstallNatives() {
|
||||
i < Natives::GetBuiltinsCount();
|
||||
i++) {
|
||||
if (!CompileBuiltin(i)) return false;
|
||||
// TODO(ager): We really only need to install the JS builtin
|
||||
// functions on the builtins object after compiling and running
|
||||
// runtime.js.
|
||||
if (!InstallJSBuiltins(builtins)) return false;
|
||||
}
|
||||
|
||||
// Setup natives with lazy loading.
|
||||
@ -1377,6 +1262,22 @@ bool Genesis::InstallExtension(v8::RegisteredExtension* current) {
|
||||
}
|
||||
|
||||
|
||||
bool Genesis::InstallJSBuiltins(Handle<JSBuiltinsObject> builtins) {
|
||||
HandleScope scope;
|
||||
for (int i = 0; i < Builtins::NumberOfJavaScriptBuiltins(); i++) {
|
||||
Builtins::JavaScript id = static_cast<Builtins::JavaScript>(i);
|
||||
Handle<String> name = Factory::LookupAsciiSymbol(Builtins::GetName(id));
|
||||
Handle<JSFunction> function
|
||||
= Handle<JSFunction>(JSFunction::cast(builtins->GetProperty(*name)));
|
||||
builtins->set_javascript_builtin(id, *function);
|
||||
Handle<SharedFunctionInfo> shared
|
||||
= Handle<SharedFunctionInfo>(function->shared());
|
||||
if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Genesis::ConfigureGlobalObjects(
|
||||
v8::Handle<v8::ObjectTemplate> global_proxy_template) {
|
||||
Handle<JSObject> global_proxy(
|
||||
|
@ -59,9 +59,6 @@ class Bootstrapper : public AllStatic {
|
||||
Handle<JSFunction>* handle);
|
||||
static void NativesCacheAdd(Vector<const char> name, Handle<JSFunction> fun);
|
||||
|
||||
// Append code that needs fixup at the end of boot strapping.
|
||||
static void AddFixup(Code* code, MacroAssembler* masm);
|
||||
|
||||
// Tells whether bootstrapping is active.
|
||||
static bool IsActive();
|
||||
|
||||
|
@ -168,28 +168,6 @@ static inline bool CalledAsConstructor() {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
|
||||
Code* code = Builtins::builtin(Builtins::Illegal);
|
||||
*resolved = false;
|
||||
|
||||
if (Top::context() != NULL) {
|
||||
Object* object = Top::builtins()->javascript_builtin(id);
|
||||
if (object->IsJSFunction()) {
|
||||
Handle<SharedFunctionInfo> shared(JSFunction::cast(object)->shared());
|
||||
// Make sure the number of parameters match the formal parameter count.
|
||||
ASSERT(shared->formal_parameter_count() ==
|
||||
Builtins::GetArgumentsCount(id));
|
||||
if (EnsureCompiled(shared, CLEAR_EXCEPTION)) {
|
||||
code = shared->code();
|
||||
*resolved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Handle<Code>(code);
|
||||
}
|
||||
|
||||
|
||||
BUILTIN(Illegal) {
|
||||
UNREACHABLE();
|
||||
return Heap::undefined_value(); // Make compiler happy.
|
||||
@ -930,9 +908,6 @@ void Builtins::Setup(bool create_heap_objects) {
|
||||
v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
|
||||
}
|
||||
}
|
||||
// Add any unresolved jumps or calls to the fixup list in the
|
||||
// bootstrapper.
|
||||
Bootstrapper::AddFixup(Code::cast(code), &masm);
|
||||
// Log the event and add the code to the builtins array.
|
||||
LOG(CodeCreateEvent(Logger::BUILTIN_TAG,
|
||||
Code::cast(code), functions[i].s_name));
|
||||
|
@ -61,9 +61,6 @@ void CodeStub::GenerateCode(MacroAssembler* masm) {
|
||||
void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
|
||||
code->set_major_key(MajorKey());
|
||||
|
||||
// Add unresolved entries in the code to the fixup list.
|
||||
Bootstrapper::AddFixup(code, masm);
|
||||
|
||||
#ifdef ENABLE_OPROFILE_AGENT
|
||||
// Register the generated stub with the OPROFILE agent.
|
||||
OProfileAgent::CreateNativeCodeRegion(GetName(),
|
||||
|
@ -197,9 +197,6 @@ Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
|
||||
Handle<Code> code =
|
||||
Factory::NewCode(desc, &sinfo, flags, masm->CodeObject());
|
||||
|
||||
// Add unresolved entries in the code to the fixup list.
|
||||
Bootstrapper::AddFixup(*code, masm);
|
||||
|
||||
#ifdef ENABLE_DISASSEMBLER
|
||||
bool print_code = Bootstrapper::IsActive()
|
||||
? FLAG_print_builtin_code
|
||||
|
@ -41,7 +41,6 @@ namespace internal {
|
||||
|
||||
MacroAssembler::MacroAssembler(void* buffer, int size)
|
||||
: Assembler(buffer, size),
|
||||
unresolved_(0),
|
||||
generating_stub_(false),
|
||||
allow_stub_calls_(true),
|
||||
code_object_(Heap::undefined_value()) {
|
||||
@ -1367,9 +1366,6 @@ void MacroAssembler::InvokeFunction(Register fun,
|
||||
|
||||
|
||||
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
|
||||
bool resolved;
|
||||
Handle<Code> code = ResolveBuiltin(id, &resolved);
|
||||
|
||||
// Calls are not allowed in some stubs.
|
||||
ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
|
||||
|
||||
@ -1377,55 +1373,22 @@ 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);
|
||||
InvokeCode(Handle<Code>(code), expected, expected,
|
||||
RelocInfo::CODE_TARGET, flag);
|
||||
|
||||
const char* name = Builtins::GetName(id);
|
||||
int argc = Builtins::GetArgumentsCount(id);
|
||||
|
||||
if (!resolved) {
|
||||
uint32_t flags =
|
||||
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
|
||||
Bootstrapper::FixupFlagsUseCodeObject::encode(false);
|
||||
Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
|
||||
unresolved_.Add(entry);
|
||||
}
|
||||
GetBuiltinEntry(edx, id);
|
||||
InvokeCode(Operand(edx), expected, expected, flag);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
|
||||
bool resolved;
|
||||
Handle<Code> code = ResolveBuiltin(id, &resolved);
|
||||
|
||||
const char* name = Builtins::GetName(id);
|
||||
int argc = Builtins::GetArgumentsCount(id);
|
||||
|
||||
mov(Operand(target), Immediate(code));
|
||||
if (!resolved) {
|
||||
uint32_t flags =
|
||||
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
|
||||
Bootstrapper::FixupFlagsUseCodeObject::encode(true);
|
||||
Unresolved entry = { pc_offset() - sizeof(int32_t), flags, name };
|
||||
unresolved_.Add(entry);
|
||||
}
|
||||
add(Operand(target), Immediate(Code::kHeaderSize - kHeapObjectTag));
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
|
||||
bool* resolved) {
|
||||
// Move the builtin function into the temporary function slot by
|
||||
// reading it from the builtins object. NOTE: We should be able to
|
||||
// reduce this to two instructions by putting the function table in
|
||||
// the global object instead of the "builtins" object and by using a
|
||||
// real register for the function.
|
||||
mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||
mov(edx, FieldOperand(edx, GlobalObject::kBuiltinsOffset));
|
||||
// Load the JavaScript builtin function from the builtins object.
|
||||
mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||
mov(edi, FieldOperand(edi, GlobalObject::kBuiltinsOffset));
|
||||
int builtins_offset =
|
||||
JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
|
||||
mov(edi, FieldOperand(edx, builtins_offset));
|
||||
|
||||
return Builtins::GetCode(id, resolved);
|
||||
mov(edi, FieldOperand(edi, builtins_offset));
|
||||
// Load the code entry point from the function into the target register.
|
||||
mov(target, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
|
||||
mov(target, FieldOperand(target, SharedFunctionInfo::kCodeOffset));
|
||||
add(Operand(target), Immediate(Code::kHeaderSize - kHeapObjectTag));
|
||||
}
|
||||
|
||||
|
||||
|
@ -390,13 +390,6 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
void Move(Register target, Handle<Object> value);
|
||||
|
||||
struct Unresolved {
|
||||
int pc;
|
||||
uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders.
|
||||
const char* name;
|
||||
};
|
||||
List<Unresolved>* unresolved() { return &unresolved_; }
|
||||
|
||||
Handle<Object> CodeObject() { return code_object_; }
|
||||
|
||||
|
||||
@ -441,7 +434,6 @@ class MacroAssembler: public Assembler {
|
||||
Label *on_not_flat_ascii_strings);
|
||||
|
||||
private:
|
||||
List<Unresolved> unresolved_;
|
||||
bool generating_stub_;
|
||||
bool allow_stub_calls_;
|
||||
// This handle will be patched with the code object on installation.
|
||||
@ -455,18 +447,6 @@ class MacroAssembler: public Assembler {
|
||||
Label* done,
|
||||
InvokeFlag flag);
|
||||
|
||||
// Prepares for a call or jump to a builtin by doing two things:
|
||||
// 1. Emits code that fetches the builtin's function object from the context
|
||||
// at runtime, and puts it in the register rdi.
|
||||
// 2. Fetches the builtin's code object, and returns it in a handle, at
|
||||
// compile time, so that later code can emit instructions to jump or call
|
||||
// the builtin directly. If the code object has not yet been created, it
|
||||
// returns the builtin code object for IllegalFunction, and sets the
|
||||
// output parameter "resolved" to false. Code that uses the return value
|
||||
// should then add the address and the builtin name to the list of fixups
|
||||
// called unresolved_, which is fixed up by the bootstrapper.
|
||||
Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
|
||||
|
||||
// Activation support.
|
||||
void EnterFrame(StackFrame::Type type);
|
||||
void LeaveFrame(StackFrame::Type type);
|
||||
|
@ -39,7 +39,6 @@ namespace internal {
|
||||
|
||||
MacroAssembler::MacroAssembler(void* buffer, int size)
|
||||
: Assembler(buffer, size),
|
||||
unresolved_(0),
|
||||
generating_stub_(false),
|
||||
allow_stub_calls_(true),
|
||||
code_object_(Heap::undefined_value()) {
|
||||
@ -415,38 +414,30 @@ void MacroAssembler::JumpToRuntime(const ExternalReference& ext,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
|
||||
// Calls are not allowed in some stubs.
|
||||
ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
|
||||
|
||||
// Rely on the assertion to check that the number of provided
|
||||
// arguments match the expected number of arguments. Fake a
|
||||
// parameter count to avoid emitting code to do the check.
|
||||
ParameterCount expected(0);
|
||||
GetBuiltinEntry(rdx, id);
|
||||
InvokeCode(rdx, expected, expected, flag);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
|
||||
bool resolved;
|
||||
Handle<Code> code = ResolveBuiltin(id, &resolved);
|
||||
|
||||
const char* name = Builtins::GetName(id);
|
||||
int argc = Builtins::GetArgumentsCount(id);
|
||||
|
||||
movq(target, code, RelocInfo::EMBEDDED_OBJECT);
|
||||
if (!resolved) {
|
||||
uint32_t flags =
|
||||
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
|
||||
Bootstrapper::FixupFlagsUseCodeObject::encode(true);
|
||||
Unresolved entry = { pc_offset() - sizeof(intptr_t), flags, name };
|
||||
unresolved_.Add(entry);
|
||||
}
|
||||
addq(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
||||
}
|
||||
|
||||
Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
|
||||
bool* resolved) {
|
||||
// Move the builtin function into the temporary function slot by
|
||||
// reading it from the builtins object. NOTE: We should be able to
|
||||
// reduce this to two instructions by putting the function table in
|
||||
// the global object instead of the "builtins" object and by using a
|
||||
// real register for the function.
|
||||
movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||
movq(rdx, FieldOperand(rdx, GlobalObject::kBuiltinsOffset));
|
||||
// Load the JavaScript builtin function from the builtins object.
|
||||
movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||
movq(rdi, FieldOperand(rdi, GlobalObject::kBuiltinsOffset));
|
||||
int builtins_offset =
|
||||
JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
|
||||
movq(rdi, FieldOperand(rdx, builtins_offset));
|
||||
|
||||
return Builtins::GetCode(id, resolved);
|
||||
movq(rdi, FieldOperand(rdi, builtins_offset));
|
||||
// Load the code entry point from the function into the target register.
|
||||
movq(target, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
|
||||
movq(target, FieldOperand(target, SharedFunctionInfo::kCodeOffset));
|
||||
addq(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
||||
}
|
||||
|
||||
|
||||
@ -1784,38 +1775,6 @@ void MacroAssembler::DebugBreak() {
|
||||
#endif // ENABLE_DEBUGGER_SUPPORT
|
||||
|
||||
|
||||
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
|
||||
bool resolved;
|
||||
Handle<Code> code = ResolveBuiltin(id, &resolved);
|
||||
|
||||
// Calls are not allowed in some stubs.
|
||||
ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
|
||||
|
||||
// Rely on the assertion to check that the number of provided
|
||||
// arguments match the expected number of arguments. Fake a
|
||||
// parameter count to avoid emitting code to do the check.
|
||||
ParameterCount expected(0);
|
||||
InvokeCode(Handle<Code>(code),
|
||||
expected,
|
||||
expected,
|
||||
RelocInfo::CODE_TARGET,
|
||||
flag);
|
||||
|
||||
const char* name = Builtins::GetName(id);
|
||||
int argc = Builtins::GetArgumentsCount(id);
|
||||
// The target address for the jump is stored as an immediate at offset
|
||||
// kInvokeCodeAddressOffset.
|
||||
if (!resolved) {
|
||||
uint32_t flags =
|
||||
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
|
||||
Bootstrapper::FixupFlagsUseCodeObject::encode(false);
|
||||
Unresolved entry =
|
||||
{ pc_offset() - kCallTargetAddressOffset, flags, name };
|
||||
unresolved_.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
|
||||
const ParameterCount& actual,
|
||||
Handle<Code> code_constant,
|
||||
|
@ -680,13 +680,6 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
void Ret();
|
||||
|
||||
struct Unresolved {
|
||||
int pc;
|
||||
uint32_t flags; // see Bootstrapper::FixupFlags decoders/encoders.
|
||||
const char* name;
|
||||
};
|
||||
List<Unresolved>* unresolved() { return &unresolved_; }
|
||||
|
||||
Handle<Object> CodeObject() { return code_object_; }
|
||||
|
||||
|
||||
@ -718,7 +711,6 @@ class MacroAssembler: public Assembler {
|
||||
bool allow_stub_calls() { return allow_stub_calls_; }
|
||||
|
||||
private:
|
||||
List<Unresolved> unresolved_;
|
||||
bool generating_stub_;
|
||||
bool allow_stub_calls_;
|
||||
// This handle will be patched with the code object on installation.
|
||||
@ -732,18 +724,6 @@ class MacroAssembler: public Assembler {
|
||||
Label* done,
|
||||
InvokeFlag flag);
|
||||
|
||||
// Prepares for a call or jump to a builtin by doing two things:
|
||||
// 1. Emits code that fetches the builtin's function object from the context
|
||||
// at runtime, and puts it in the register rdi.
|
||||
// 2. Fetches the builtin's code object, and returns it in a handle, at
|
||||
// compile time, so that later code can emit instructions to jump or call
|
||||
// the builtin directly. If the code object has not yet been created, it
|
||||
// returns the builtin code object for IllegalFunction, and sets the
|
||||
// output parameter "resolved" to false. Code that uses the return value
|
||||
// should then add the address and the builtin name to the list of fixups
|
||||
// called unresolved_, which is fixed up by the bootstrapper.
|
||||
Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
|
||||
|
||||
// Activation support.
|
||||
void EnterFrame(StackFrame::Type type);
|
||||
void LeaveFrame(StackFrame::Type type);
|
||||
|
Loading…
Reference in New Issue
Block a user