Add constant splitting for user controlled constants in the full compiler

This is IA32 only for now.

Added a random value to each assembler instance (JIT cookie) to be used for constant splitting. Added safe versions of setting a register with an immediate value and for pushing an immediate value. Used these functions where user controlled immediate values could be emitted in the code stream. I also used it for immediates which are an argument number even though the number of formal arguments is currently limited to 16k.

I found no compares directly with user controlled constants.

I am not sure whether the test is that useful, but it might catch some changes missing constant splitting.

Review URL: http://codereview.chromium.org//7005031

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7868 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
sgjesse@chromium.org 2011-05-11 14:16:24 +00:00
parent 26bf1dfd4a
commit 4e18d50834
8 changed files with 123 additions and 18 deletions

View File

@ -73,6 +73,18 @@ const double DoubleConstant::nan = OS::nan_value();
const double DoubleConstant::negative_infinity = -V8_INFINITY;
const char* RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
// -----------------------------------------------------------------------------
// Implementation of AssemblerBase
AssemblerBase::AssemblerBase(Isolate* isolate)
: isolate_(isolate),
jit_cookie_(0) {
if (FLAG_mask_constants_with_cookie && isolate != NULL) {
jit_cookie_ = V8::RandomPrivate(isolate);
}
}
// -----------------------------------------------------------------------------
// Implementation of Label

View File

@ -49,12 +49,14 @@ const unsigned kNoASTId = -1;
class AssemblerBase: public Malloced {
public:
explicit AssemblerBase(Isolate* isolate) : isolate_(isolate) {}
explicit AssemblerBase(Isolate* isolate);
Isolate* isolate() const { return isolate_; }
int jit_cookie() { return jit_cookie_; }
private:
Isolate* isolate_;
int jit_cookie_;
};
// -----------------------------------------------------------------------------

View File

@ -279,6 +279,7 @@ class Immediate BASE_EMBEDDED {
RelocInfo::Mode rmode_;
friend class Assembler;
friend class MacroAssembler;
};

View File

@ -201,7 +201,7 @@ void FullCodeGenerator::Generate(CompilationInfo* info) {
__ lea(edx,
Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
__ push(edx);
__ push(Immediate(Smi::FromInt(scope()->num_parameters())));
__ SafePush(Immediate(Smi::FromInt(scope()->num_parameters())));
// Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count.
// The stub will rewrite receiver and parameter count if the previous
@ -390,13 +390,20 @@ void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
void FullCodeGenerator::AccumulatorValueContext::Plug(
Handle<Object> lit) const {
__ Set(result_register(), Immediate(lit));
if (lit->IsSmi()) {
__ SafeSet(result_register(), Immediate(lit));
} else {
__ Set(result_register(), Immediate(lit));
}
}
void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
// Immediates can be pushed directly.
__ push(Immediate(lit));
if (lit->IsSmi()) {
__ SafePush(Immediate(lit));
} else {
__ push(Immediate(lit));
}
}
@ -739,7 +746,7 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
}
ASSERT(prop->key()->AsLiteral() != NULL &&
prop->key()->AsLiteral()->handle()->IsSmi());
__ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
__ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle()));
Handle<Code> ic = is_strict_mode()
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
@ -1193,7 +1200,7 @@ void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
__ mov(edx,
ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
slow));
__ mov(eax, Immediate(key_literal->handle()));
__ SafeSet(eax, Immediate(key_literal->handle()));
Handle<Code> ic =
isolate()->builtins()->KeyedLoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
@ -1278,7 +1285,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) {
ASSERT(key_literal->handle()->IsSmi());
// Load the key.
__ mov(eax, Immediate(key_literal->handle()));
__ SafeSet(eax, Immediate(key_literal->handle()));
// Do a keyed property load.
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
@ -1549,7 +1556,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
MemOperand slot_operand =
EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
__ push(slot_operand);
__ mov(eax, Immediate(property->key()->AsLiteral()->handle()));
__ SafeSet(eax, Immediate(property->key()->AsLiteral()->handle()));
} else {
VisitForStackValue(property->obj());
VisitForAccumulatorValue(property->key());
@ -1562,7 +1569,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
MemOperand slot_operand =
EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
__ push(slot_operand);
__ push(Immediate(property->key()->AsLiteral()->handle()));
__ SafePush(Immediate(property->key()->AsLiteral()->handle()));
} else {
VisitForStackValue(property->obj());
VisitForStackValue(property->key());
@ -1641,6 +1648,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral();
ASSERT(!key->handle()->IsSmi());
__ mov(ecx, Immediate(key->handle()));
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
@ -1807,7 +1815,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
}
__ mov(edx, eax);
__ Set(ecx, Immediate(prop->key()->AsLiteral()->handle()));
__ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle()));
} else {
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());
@ -2320,7 +2328,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
SetSourcePosition(expr->position());
// Load function and argument count into edi and eax.
__ Set(eax, Immediate(arg_count));
__ SafeSet(eax, Immediate(arg_count));
__ mov(edi, Operand(esp, arg_count * kPointerSize));
Handle<Code> construct_builtin =
@ -2660,7 +2668,7 @@ void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
// parameter count in eax.
VisitForAccumulatorValue(args->at(0));
__ mov(edx, eax);
__ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
__ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
__ CallStub(&stub);
context()->Plug(eax);
@ -2672,7 +2680,7 @@ void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
Label exit;
// Get the number of formal parameters.
__ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
__ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
// Check if the calling frame is an arguments adaptor frame.
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
@ -3813,7 +3821,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
MemOperand slot_operand =
EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx);
__ push(slot_operand);
__ mov(eax, Immediate(prop->key()->AsLiteral()->handle()));
__ SafeSet(eax, Immediate(prop->key()->AsLiteral()->handle()));
} else {
VisitForStackValue(prop->obj());
VisitForAccumulatorValue(prop->key());

View File

@ -191,7 +191,7 @@ void MacroAssembler::DebugBreak() {
void MacroAssembler::Set(Register dst, const Immediate& x) {
if (x.is_zero()) {
xor_(dst, Operand(dst)); // shorter than mov
xor_(dst, Operand(dst)); // Shorter than mov.
} else {
mov(dst, x);
}
@ -203,6 +203,33 @@ void MacroAssembler::Set(const Operand& dst, const Immediate& x) {
}
bool MacroAssembler::IsUnsafeImmediate(const Immediate& x) {
static const int kMaxImmediateBits = 17;
if (x.rmode_ != RelocInfo::NONE) return false;
return !is_intn(x.x_, kMaxImmediateBits);
}
void MacroAssembler::SafeSet(Register dst, const Immediate& x) {
if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
Set(dst, Immediate(x.x_ ^ jit_cookie()));
xor_(dst, jit_cookie());
} else {
Set(dst, x);
}
}
void MacroAssembler::SafePush(const Immediate& x) {
if (IsUnsafeImmediate(x) && jit_cookie() != 0) {
push(Immediate(x.x_ ^ jit_cookie()));
xor_(Operand(esp, 0), Immediate(jit_cookie()));
} else {
push(x);
}
}
void MacroAssembler::CmpObjectType(Register heap_object,
InstanceType type,
Register map) {

View File

@ -193,6 +193,11 @@ class MacroAssembler: public Assembler {
void Set(Register dst, const Immediate& x);
void Set(const Operand& dst, const Immediate& x);
// Support for constant splitting.
bool IsUnsafeImmediate(const Immediate& x);
void SafeSet(Register dst, const Immediate& x);
void SafePush(const Immediate& x);
// Compare object type for heap object.
// Incoming register is heap_object and outgoing register is map.
void CmpObjectType(Register heap_object, InstanceType type, Register map);

View File

@ -31,6 +31,8 @@
#include "v8.h"
#include "compiler.h"
#include "disasm.h"
#include "disassembler.h"
#include "execution.h"
#include "factory.h"
#include "platform.h"
@ -348,3 +350,51 @@ TEST(GetScriptLineNumber) {
CHECK_EQ(i, f->GetScriptLineNumber());
}
}
#ifdef ENABLE_DISASSEMBLER
static Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj,
const char* property_name) {
v8::Local<v8::Function> fun =
v8::Local<v8::Function>::Cast(obj->Get(v8_str(property_name)));
return v8::Utils::OpenHandle(*fun);
}
static void CheckCodeForUnsafeLiteral(Handle<JSFunction> f) {
// Create a disassembler with default name lookup.
disasm::NameConverter name_converter;
disasm::Disassembler d(name_converter);
if (f->code()->kind() == Code::FUNCTION) {
Address pc = f->code()->instruction_start();
int decode_size =
Min(f->code()->instruction_size(),
static_cast<int>(f->code()->stack_check_table_offset()));
Address end = pc + decode_size;
v8::internal::EmbeddedVector<char, 128> decode_buffer;
while (pc < end) {
pc += d.InstructionDecode(decode_buffer, pc);
CHECK(strstr(decode_buffer.start(), "mov eax,0x178c29c") == NULL);
CHECK(strstr(decode_buffer.start(), "push 0x178c29c") == NULL);
CHECK(strstr(decode_buffer.start(), "0x178c29c") == NULL);
}
}
}
TEST(SplitConstantsInFullCompiler) {
v8::HandleScope scope;
LocalContext env;
CompileRun("function f() { a = 12345678 }; f();");
CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
CompileRun("function f(x) { a = 12345678 + x}; f(1);");
CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
CompileRun("function f(x) { var arguments = 1; x += 12345678}; f(1);");
CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
CompileRun("function f(x) { var arguments = 1; x = 12345678}; f(1);");
CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
}
#endif

View File

@ -97,8 +97,8 @@ class AllowNativesSyntaxNoInlining {
};
Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj,
const char* property_name) {
static Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj,
const char* property_name) {
v8::Local<v8::Function> fun =
v8::Local<v8::Function>::Cast(obj->Get(v8_str(property_name)));
return v8::Utils::OpenHandle(*fun);