Commit 638cb4f9 authored by ager@chromium.org's avatar ager@chromium.org

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
parent 4f7b9e4d
...@@ -37,7 +37,6 @@ namespace internal { ...@@ -37,7 +37,6 @@ namespace internal {
MacroAssembler::MacroAssembler(void* buffer, int size) MacroAssembler::MacroAssembler(void* buffer, int size)
: Assembler(buffer, size), : Assembler(buffer, size),
unresolved_(0),
generating_stub_(false), generating_stub_(false),
allow_stub_calls_(true), allow_stub_calls_(true),
code_object_(Heap::undefined_value()) { code_object_(Heap::undefined_value()) {
...@@ -1233,58 +1232,28 @@ void MacroAssembler::JumpToRuntime(const ExternalReference& builtin) { ...@@ -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, void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
InvokeJSFlags flags) { InvokeJSFlags flags) {
bool resolved; GetBuiltinEntry(r2, id);
Handle<Code> code = ResolveBuiltin(id, &resolved);
if (flags == CALL_JS) { if (flags == CALL_JS) {
Call(code, RelocInfo::CODE_TARGET); Call(r2);
} else { } else {
ASSERT(flags == JUMP_JS); ASSERT(flags == JUMP_JS);
Jump(code, RelocInfo::CODE_TARGET); Jump(r2);
}
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);
} }
} }
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
bool resolved; // Load the JavaScript builtin function from the builtins object.
Handle<Code> code = ResolveBuiltin(id, &resolved); ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
ldr(r1, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
mov(target, Operand(code)); int builtins_offset =
if (!resolved) { JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
const char* name = Builtins::GetName(id); ldr(r1, FieldMemOperand(r1, builtins_offset));
int argc = Builtins::GetArgumentsCount(id); // Load the code entry point from the function into the target register.
uint32_t flags = ldr(target, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) | ldr(target, FieldMemOperand(target, SharedFunctionInfo::kCodeOffset));
Bootstrapper::FixupFlagsUseCodeObject::encode(true);
Unresolved entry = { pc_offset() - kInstrSize, flags, name };
unresolved_.Add(entry);
}
add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag)); add(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
} }
......
...@@ -353,13 +353,6 @@ class MacroAssembler: public Assembler { ...@@ -353,13 +353,6 @@ class MacroAssembler: public Assembler {
// setup the function in r1. // setup the function in r1.
void GetBuiltinEntry(Register target, Builtins::JavaScript id); 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_; } Handle<Object> CodeObject() { return code_object_; }
...@@ -432,23 +425,10 @@ class MacroAssembler: public Assembler { ...@@ -432,23 +425,10 @@ class MacroAssembler: public Assembler {
Label* done, Label* done,
InvokeFlag flag); 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. // Activation support.
void EnterFrame(StackFrame::Type type); void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type); void LeaveFrame(StackFrame::Type type);
List<Unresolved> unresolved_;
bool generating_stub_; bool generating_stub_;
bool allow_stub_calls_; bool allow_stub_calls_;
// This handle will be patched with the code object on installation. // This handle will be patched with the code object on installation.
......
...@@ -192,116 +192,6 @@ void Bootstrapper::TearDown() { ...@@ -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 { class Genesis BASE_EMBEDDED {
public: public:
Genesis(Handle<Object> global_object, Genesis(Handle<Object> global_object,
...@@ -338,6 +228,7 @@ class Genesis BASE_EMBEDDED { ...@@ -338,6 +228,7 @@ class Genesis BASE_EMBEDDED {
bool InstallExtension(const char* name); bool InstallExtension(const char* name);
bool InstallExtension(v8::RegisteredExtension* current); bool InstallExtension(v8::RegisteredExtension* current);
bool InstallSpecialObjects(); bool InstallSpecialObjects();
bool InstallJSBuiltins(Handle<JSBuiltinsObject> builtins);
bool ConfigureApiObject(Handle<JSObject> object, bool ConfigureApiObject(Handle<JSObject> object,
Handle<ObjectTemplateInfo> object_template); Handle<ObjectTemplateInfo> object_template);
bool ConfigureGlobalObjects(v8::Handle<v8::ObjectTemplate> global_template); bool ConfigureGlobalObjects(v8::Handle<v8::ObjectTemplate> global_template);
...@@ -379,15 +270,6 @@ void Bootstrapper::Iterate(ObjectVisitor* v) { ...@@ -379,15 +270,6 @@ void Bootstrapper::Iterate(ObjectVisitor* v) {
v->Synchronize("NativesCache"); v->Synchronize("NativesCache");
extensions_cache.Iterate(v); extensions_cache.Iterate(v);
v->Synchronize("Extensions"); 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, ...@@ -968,8 +850,7 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
Handle<Object> result = Handle<Object> result =
Execution::Call(fun, receiver, 0, NULL, &has_pending_exception); Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
if (has_pending_exception) return false; if (has_pending_exception) return false;
return PendingFixups::Process( return true;
Handle<JSBuiltinsObject>(Top::context()->builtins()));
} }
...@@ -1176,6 +1057,10 @@ bool Genesis::InstallNatives() { ...@@ -1176,6 +1057,10 @@ bool Genesis::InstallNatives() {
i < Natives::GetBuiltinsCount(); i < Natives::GetBuiltinsCount();
i++) { i++) {
if (!CompileBuiltin(i)) return false; 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. // Setup natives with lazy loading.
...@@ -1377,6 +1262,22 @@ bool Genesis::InstallExtension(v8::RegisteredExtension* current) { ...@@ -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( bool Genesis::ConfigureGlobalObjects(
v8::Handle<v8::ObjectTemplate> global_proxy_template) { v8::Handle<v8::ObjectTemplate> global_proxy_template) {
Handle<JSObject> global_proxy( Handle<JSObject> global_proxy(
......
...@@ -59,9 +59,6 @@ class Bootstrapper : public AllStatic { ...@@ -59,9 +59,6 @@ class Bootstrapper : public AllStatic {
Handle<JSFunction>* handle); Handle<JSFunction>* handle);
static void NativesCacheAdd(Vector<const char> name, Handle<JSFunction> fun); 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. // Tells whether bootstrapping is active.
static bool IsActive(); static bool IsActive();
......
...@@ -168,28 +168,6 @@ static inline bool CalledAsConstructor() { ...@@ -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) { BUILTIN(Illegal) {
UNREACHABLE(); UNREACHABLE();
return Heap::undefined_value(); // Make compiler happy. return Heap::undefined_value(); // Make compiler happy.
...@@ -930,9 +908,6 @@ void Builtins::Setup(bool create_heap_objects) { ...@@ -930,9 +908,6 @@ void Builtins::Setup(bool create_heap_objects) {
v8::internal::V8::FatalProcessOutOfMemory("CreateCode"); 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 the event and add the code to the builtins array.
LOG(CodeCreateEvent(Logger::BUILTIN_TAG, LOG(CodeCreateEvent(Logger::BUILTIN_TAG,
Code::cast(code), functions[i].s_name)); Code::cast(code), functions[i].s_name));
......
...@@ -61,9 +61,6 @@ void CodeStub::GenerateCode(MacroAssembler* masm) { ...@@ -61,9 +61,6 @@ void CodeStub::GenerateCode(MacroAssembler* masm) {
void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) { void CodeStub::RecordCodeGeneration(Code* code, MacroAssembler* masm) {
code->set_major_key(MajorKey()); code->set_major_key(MajorKey());
// Add unresolved entries in the code to the fixup list.
Bootstrapper::AddFixup(code, masm);
#ifdef ENABLE_OPROFILE_AGENT #ifdef ENABLE_OPROFILE_AGENT
// Register the generated stub with the OPROFILE agent. // Register the generated stub with the OPROFILE agent.
OProfileAgent::CreateNativeCodeRegion(GetName(), OProfileAgent::CreateNativeCodeRegion(GetName(),
......
...@@ -197,9 +197,6 @@ Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm, ...@@ -197,9 +197,6 @@ Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
Handle<Code> code = Handle<Code> code =
Factory::NewCode(desc, &sinfo, flags, masm->CodeObject()); Factory::NewCode(desc, &sinfo, flags, masm->CodeObject());
// Add unresolved entries in the code to the fixup list.
Bootstrapper::AddFixup(*code, masm);
#ifdef ENABLE_DISASSEMBLER #ifdef ENABLE_DISASSEMBLER
bool print_code = Bootstrapper::IsActive() bool print_code = Bootstrapper::IsActive()
? FLAG_print_builtin_code ? FLAG_print_builtin_code
......
...@@ -41,7 +41,6 @@ namespace internal { ...@@ -41,7 +41,6 @@ namespace internal {
MacroAssembler::MacroAssembler(void* buffer, int size) MacroAssembler::MacroAssembler(void* buffer, int size)
: Assembler(buffer, size), : Assembler(buffer, size),
unresolved_(0),
generating_stub_(false), generating_stub_(false),
allow_stub_calls_(true), allow_stub_calls_(true),
code_object_(Heap::undefined_value()) { code_object_(Heap::undefined_value()) {
...@@ -1367,9 +1366,6 @@ void MacroAssembler::InvokeFunction(Register fun, ...@@ -1367,9 +1366,6 @@ void MacroAssembler::InvokeFunction(Register fun,
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) { void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
bool resolved;
Handle<Code> code = ResolveBuiltin(id, &resolved);
// Calls are not allowed in some stubs. // Calls are not allowed in some stubs.
ASSERT(flag == JUMP_FUNCTION || allow_stub_calls()); ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
...@@ -1377,55 +1373,22 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) { ...@@ -1377,55 +1373,22 @@ void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
// arguments match the expected number of arguments. Fake a // arguments match the expected number of arguments. Fake a
// parameter count to avoid emitting code to do the check. // parameter count to avoid emitting code to do the check.
ParameterCount expected(0); ParameterCount expected(0);
InvokeCode(Handle<Code>(code), expected, expected, GetBuiltinEntry(edx, id);
RelocInfo::CODE_TARGET, flag); InvokeCode(Operand(edx), expected, expected, 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);
}
} }
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
bool resolved; // Load the JavaScript builtin function from the builtins object.
Handle<Code> code = ResolveBuiltin(id, &resolved); mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
mov(edi, FieldOperand(edi, GlobalObject::kBuiltinsOffset));
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));
int builtins_offset = int builtins_offset =
JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize); JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
mov(edi, FieldOperand(edx, builtins_offset)); mov(edi, FieldOperand(edi, builtins_offset));
// Load the code entry point from the function into the target register.
return Builtins::GetCode(id, resolved); 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 { ...@@ -390,13 +390,6 @@ class MacroAssembler: public Assembler {
void Move(Register target, Handle<Object> value); 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_; } Handle<Object> CodeObject() { return code_object_; }
...@@ -441,7 +434,6 @@ class MacroAssembler: public Assembler { ...@@ -441,7 +434,6 @@ class MacroAssembler: public Assembler {
Label *on_not_flat_ascii_strings); Label *on_not_flat_ascii_strings);
private: private:
List<Unresolved> unresolved_;
bool generating_stub_; bool generating_stub_;
bool allow_stub_calls_; bool allow_stub_calls_;
// This handle will be patched with the code object on installation. // This handle will be patched with the code object on installation.
...@@ -455,18 +447,6 @@ class MacroAssembler: public Assembler { ...@@ -455,18 +447,6 @@ class MacroAssembler: public Assembler {
Label* done, Label* done,
InvokeFlag flag); 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. // Activation support.
void EnterFrame(StackFrame::Type type); void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type); void LeaveFrame(StackFrame::Type type);
......
...@@ -39,7 +39,6 @@ namespace internal { ...@@ -39,7 +39,6 @@ namespace internal {
MacroAssembler::MacroAssembler(void* buffer, int size) MacroAssembler::MacroAssembler(void* buffer, int size)
: Assembler(buffer, size), : Assembler(buffer, size),
unresolved_(0),
generating_stub_(false), generating_stub_(false),
allow_stub_calls_(true), allow_stub_calls_(true),
code_object_(Heap::undefined_value()) { code_object_(Heap::undefined_value()) {
...@@ -415,38 +414,30 @@ void MacroAssembler::JumpToRuntime(const ExternalReference& ext, ...@@ -415,38 +414,30 @@ void MacroAssembler::JumpToRuntime(const ExternalReference& ext,
} }
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) { void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) {
bool resolved; // Calls are not allowed in some stubs.
Handle<Code> code = ResolveBuiltin(id, &resolved); ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());
const char* name = Builtins::GetName(id);
int argc = Builtins::GetArgumentsCount(id);
movq(target, code, RelocInfo::EMBEDDED_OBJECT); // Rely on the assertion to check that the number of provided
if (!resolved) { // arguments match the expected number of arguments. Fake a
uint32_t flags = // parameter count to avoid emitting code to do the check.
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) | ParameterCount expected(0);
Bootstrapper::FixupFlagsUseCodeObject::encode(true); GetBuiltinEntry(rdx, id);
Unresolved entry = { pc_offset() - sizeof(intptr_t), flags, name }; InvokeCode(rdx, expected, expected, flag);
unresolved_.Add(entry);
}
addq(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
} }
Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
bool* resolved) { void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
// Move the builtin function into the temporary function slot by // Load the JavaScript builtin function from the builtins object.
// reading it from the builtins object. NOTE: We should be able to movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
// reduce this to two instructions by putting the function table in movq(rdi, FieldOperand(rdi, GlobalObject::kBuiltinsOffset));
// 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));
int builtins_offset = int builtins_offset =
JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize); JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
movq(rdi, FieldOperand(rdx, builtins_offset)); movq(rdi, FieldOperand(rdi, builtins_offset));
// Load the code entry point from the function into the target register.
return Builtins::GetCode(id, resolved); 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() { ...@@ -1784,38 +1775,6 @@ void MacroAssembler::DebugBreak() {
#endif // ENABLE_DEBUGGER_SUPPORT #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, void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual, const ParameterCount& actual,
Handle<Code> code_constant, Handle<Code> code_constant,
......
...@@ -680,13 +680,6 @@ class MacroAssembler: public Assembler { ...@@ -680,13 +680,6 @@ class MacroAssembler: public Assembler {
void Ret(); 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_; } Handle<Object> CodeObject() { return code_object_; }
...@@ -718,7 +711,6 @@ class MacroAssembler: public Assembler { ...@@ -718,7 +711,6 @@ class MacroAssembler: public Assembler {
bool allow_stub_calls() { return allow_stub_calls_; } bool allow_stub_calls() { return allow_stub_calls_; }
private: private:
List<Unresolved> unresolved_;
bool generating_stub_; bool generating_stub_;
bool allow_stub_calls_; bool allow_stub_calls_;
// This handle will be patched with the code object on installation. // This handle will be patched with the code object on installation.
...@@ -732,18 +724,6 @@ class MacroAssembler: public Assembler { ...@@ -732,18 +724,6 @@ class MacroAssembler: public Assembler {
Label* done, Label* done,
InvokeFlag flag); 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. // Activation support.
void EnterFrame(StackFrame::Type type); void EnterFrame(StackFrame::Type type);
void LeaveFrame(StackFrame::Type type); void LeaveFrame(StackFrame::Type type);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment