Merge math function ids and custom call generator ids.

Two old id types are replaced by builtin function ids. We can use
these in the code generators to emit custom code for the selected
functions.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6013 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
vitalyr@chromium.org 2010-12-14 18:53:48 +00:00
parent 5b55e1ad9a
commit 57e072298f
18 changed files with 139 additions and 158 deletions

View File

@ -1341,7 +1341,7 @@ LInstruction* LChunkBuilder::DoCallConstantFunction(
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
MathFunctionId op = instr->op();
BuiltinFunctionId op = instr->op();
LOperand* input = UseRegisterAtStart(instr->value());
LInstruction* result = new LUnaryMathOperation(input);
switch (op) {

View File

@ -665,7 +665,7 @@ class LUnaryMathOperation: public LUnaryOperation {
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
virtual void PrintDataTo(StringStream* stream) const;
MathFunctionId op() const { return hydrogen()->op(); }
BuiltinFunctionId op() const { return hydrogen()->op(); }
};

View File

@ -2112,8 +2112,8 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// -- lr : return address
// -----------------------------------
SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id();
if (function_info->HasBuiltinFunctionId()) {
BuiltinFunctionId id = function_info->builtin_function_id();
MaybeObject* maybe_result = CompileCustomCall(
id, object, holder, NULL, function, name);
Object* result;
@ -2323,8 +2323,8 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// -----------------------------------
SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id();
if (function_info->HasBuiltinFunctionId()) {
BuiltinFunctionId id = function_info->builtin_function_id();
MaybeObject* maybe_result = CompileCustomCall(
id, object, holder, cell, function, name);
Object* result;

View File

@ -32,6 +32,7 @@
#include "parser.h"
#include "scopes.h"
#include "string-stream.h"
#include "stub-cache.h"
namespace v8 {
namespace internal {
@ -559,16 +560,18 @@ void CaseClause::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
static bool CallWithoutIC(Handle<JSFunction> target, int arity) {
SharedFunctionInfo* info = target->shared();
if (target->NeedsArgumentsAdaption()) {
// If the number of formal parameters of the target function
// does not match the number of arguments we're passing, we
// don't want to deal with it.
return target->shared()->formal_parameter_count() == arity;
return info->formal_parameter_count() == arity;
} else {
// If the target doesn't need arguments adaption, we can call
// it directly, but we avoid to do so if it has a custom call
// generator, because that is likely to generate better code.
return !target->shared()->HasCustomCallGenerator();
return !info->HasBuiltinFunctionId() ||
!CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id());
}
}

View File

@ -38,7 +38,6 @@
#include "natives.h"
#include "objects-visiting.h"
#include "snapshot.h"
#include "stub-cache.h"
#include "extensions/externalize-string-extension.h"
#include "extensions/gc-extension.h"
@ -234,7 +233,7 @@ class Genesis BASE_EMBEDDED {
// Used for creating a context from scratch.
void InstallNativeFunctions();
bool InstallNatives();
void InstallCustomCallGenerators();
void InstallBuiltinFunctionIds();
void InstallJSFunctionResultCaches();
void InitializeNormalizedMapCaches();
// Used both for deserialized and from-scratch contexts to add the extensions
@ -1270,7 +1269,7 @@ bool Genesis::InstallNatives() {
global_context()->set_string_function_prototype_map(
HeapObject::cast(string_function->initial_map()->prototype())->map());
InstallCustomCallGenerators();
InstallBuiltinFunctionIds();
// Install Function.prototype.call and apply.
{ Handle<String> key = Factory::function_class_symbol();
@ -1369,7 +1368,7 @@ bool Genesis::InstallNatives() {
}
static Handle<JSObject> ResolveCustomCallGeneratorHolder(
static Handle<JSObject> ResolveBuiltinIdHolder(
Handle<Context> global_context,
const char* holder_expr) {
Handle<GlobalObject> global(global_context->global());
@ -1387,9 +1386,9 @@ static Handle<JSObject> ResolveCustomCallGeneratorHolder(
}
static void InstallCustomCallGenerator(Handle<JSObject> holder,
const char* function_name,
int id) {
static void InstallBuiltinFunctionId(Handle<JSObject> holder,
const char* function_name,
BuiltinFunctionId id) {
Handle<String> name = Factory::LookupAsciiSymbol(function_name);
Object* function_object = holder->GetProperty(*name)->ToObjectUnchecked();
Handle<JSFunction> function(JSFunction::cast(function_object));
@ -1397,17 +1396,17 @@ static void InstallCustomCallGenerator(Handle<JSObject> holder,
}
void Genesis::InstallCustomCallGenerators() {
void Genesis::InstallBuiltinFunctionIds() {
HandleScope scope;
#define INSTALL_CALL_GENERATOR(holder_expr, fun_name, name) \
{ \
Handle<JSObject> holder = ResolveCustomCallGeneratorHolder( \
global_context(), #holder_expr); \
const int id = CallStubCompiler::k##name##CallGenerator; \
InstallCustomCallGenerator(holder, #fun_name, id); \
#define INSTALL_BUILTIN_ID(holder_expr, fun_name, name) \
{ \
Handle<JSObject> holder = ResolveBuiltinIdHolder( \
global_context(), #holder_expr); \
BuiltinFunctionId id = k##name; \
InstallBuiltinFunctionId(holder, #fun_name, id); \
}
CUSTOM_CALL_IC_GENERATORS(INSTALL_CALL_GENERATOR)
#undef INSTALL_CALL_GENERATOR
FUNCTIONS_WITH_ID_LIST(INSTALL_BUILTIN_ID)
#undef INSTALL_BUILTIN_ID
}

View File

@ -1366,7 +1366,7 @@ class HBitNot: public HUnaryOperation {
class HUnaryMathOperation: public HUnaryOperation {
public:
HUnaryMathOperation(HValue* value, MathFunctionId op)
HUnaryMathOperation(HValue* value, BuiltinFunctionId op)
: HUnaryOperation(value), op_(op) {
switch (op) {
case kMathFloor:
@ -1381,8 +1381,10 @@ class HUnaryMathOperation: public HUnaryOperation {
case kMathSqrt:
case kMathPowHalf:
case kMathLog:
default:
set_representation(Representation::Double());
break;
default:
UNREACHABLE();
}
SetFlag(kUseGVN);
}
@ -1421,13 +1423,13 @@ class HUnaryMathOperation: public HUnaryOperation {
return this;
}
MathFunctionId op() const { return op_; }
BuiltinFunctionId op() const { return op_; }
const char* OpName() const;
DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation, "unary_math_operation")
private:
MathFunctionId op_;
BuiltinFunctionId op_;
};

View File

@ -4080,7 +4080,8 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) {
bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
// Try to inline calls like Math.* as operations in the calling function.
MathFunctionId id = expr->target()->shared()->math_function_id();
if (!expr->target()->shared()->IsBuiltinMathFunction()) return false;
BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
switch (id) {
case kMathRound:
@ -4143,7 +4144,7 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
}
break;
default:
// Either not a special math function or not yet supported for inlining.
// Not yet supported for inlining.
break;
}
return false;

View File

@ -1354,7 +1354,7 @@ LInstruction* LChunkBuilder::DoCallConstantFunction(
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
MathFunctionId op = instr->op();
BuiltinFunctionId op = instr->op();
if (op == kMathLog) {
LOperand* input = UseFixedDouble(instr->value(), xmm1);
LInstruction* result = new LUnaryMathOperation(input);

View File

@ -670,7 +670,7 @@ class LUnaryMathOperation: public LUnaryOperation {
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
virtual void PrintDataTo(StringStream* stream) const;
MathFunctionId op() const { return hydrogen()->op(); }
BuiltinFunctionId op() const { return hydrogen()->op(); }
};

View File

@ -2133,8 +2133,8 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// -----------------------------------
SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id();
if (function_info->HasBuiltinFunctionId()) {
BuiltinFunctionId id = function_info->builtin_function_id();
MaybeObject* maybe_result = CompileCustomCall(
id, object, holder, NULL, function, name);
Object* result;
@ -2375,8 +2375,8 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// -----------------------------------
SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id();
if (function_info->HasBuiltinFunctionId()) {
BuiltinFunctionId id = function_info->builtin_function_id();
MaybeObject* maybe_result = CompileCustomCall(
id, object, holder, cell, function, name);
Object* result;

View File

@ -258,16 +258,6 @@ function SetupMath() {
"max", MathMax,
"min", MathMin
));
// The values here are from the MathFunctionId enum in objects.h.
%SetMathFunctionId($Math.floor, 1);
%SetMathFunctionId($Math.round, 2);
%SetMathFunctionId($Math.abs, 4);
%SetMathFunctionId($Math.sqrt, 0xd);
%SetMathFunctionId($Math.pow, 0xe);
%SetMathFunctionId($Math.log, 5);
// TODO(erikcorry): Set the id of the other functions so they can be
// optimized.
};

View File

@ -3036,27 +3036,20 @@ FunctionTemplateInfo* SharedFunctionInfo::get_api_func_data() {
}
bool SharedFunctionInfo::HasCustomCallGenerator() {
bool SharedFunctionInfo::HasBuiltinFunctionId() {
return function_data()->IsSmi();
}
MathFunctionId SharedFunctionInfo::math_function_id() {
return static_cast<MathFunctionId>(
(compiler_hints() >> kMathFunctionShift) & kMathFunctionMask);
bool SharedFunctionInfo::IsBuiltinMathFunction() {
return HasBuiltinFunctionId() &&
builtin_function_id() >= kFirstMathFunctionId;
}
void SharedFunctionInfo::set_math_function_id(int math_fn) {
ASSERT(math_fn <= max_math_id_number());
set_compiler_hints(compiler_hints() |
((math_fn & kMathFunctionMask) << kMathFunctionShift));
}
int SharedFunctionInfo::custom_call_generator_id() {
ASSERT(HasCustomCallGenerator());
return Smi::cast(function_data())->value();
BuiltinFunctionId SharedFunctionInfo::builtin_function_id() {
ASSERT(HasBuiltinFunctionId());
return static_cast<BuiltinFunctionId>(Smi::cast(function_data())->value());
}

View File

@ -3714,24 +3714,49 @@ class Script: public Struct {
};
enum MathFunctionId {
kNotSpecialMathFunction = 0,
// These numbers must be kept in sync with the ones in math.js.
kMathFloor = 1,
kMathRound = 2,
kMathCeil = 3,
kMathAbs = 4,
kMathLog = 5,
kMathSin = 6,
kMathCos = 7,
kMathTan = 8,
kMathASin = 9,
kMathACos = 0xa,
kMathATan = 0xb,
kMathExp = 0xc,
kMathSqrt = 0xd,
kMathPow = 0xe,
kMathPowHalf = 0xf
// List of builtin functions we want to identify to improve code
// generation.
//
// Each entry has a name of a global object property holding an object
// optionally followed by ".prototype", a name of a builtin function
// on the object (the one the id is set for), and a label.
//
// Installation of ids for the selected builtin functions is handled
// by the bootstrapper.
//
// NOTE: Order is important: math functions should be at the end of
// the list and MathFloor should be the first math function.
#define FUNCTIONS_WITH_ID_LIST(V) \
V(Array.prototype, push, ArrayPush) \
V(Array.prototype, pop, ArrayPop) \
V(String.prototype, charCodeAt, StringCharCodeAt) \
V(String.prototype, charAt, StringCharAt) \
V(String, fromCharCode, StringFromCharCode) \
V(Math, floor, MathFloor) \
V(Math, round, MathRound) \
V(Math, ceil, MathCeil) \
V(Math, abs, MathAbs) \
V(Math, log, MathLog) \
V(Math, sin, MathSin) \
V(Math, cos, MathCos) \
V(Math, tan, MathTan) \
V(Math, asin, MathASin) \
V(Math, acos, MathACos) \
V(Math, atan, MathATan) \
V(Math, exp, MathExp) \
V(Math, sqrt, MathSqrt) \
V(Math, pow, MathPow)
enum BuiltinFunctionId {
#define DECLARE_FUNCTION_ID(ignored1, ignore2, name) \
k##name,
FUNCTIONS_WITH_ID_LIST(DECLARE_FUNCTION_ID)
#undef DECLARE_FUNCTION_ID
// Fake id for a special case of Math.pow. Note, it continues the
// list of math functions.
kMathPowHalf,
kFirstMathFunctionId = kMathFloor
};
@ -3872,7 +3897,7 @@ class SharedFunctionInfo: public HeapObject {
// [function data]: This field holds some additional data for function.
// Currently it either has FunctionTemplateInfo to make benefit the API
// or Smi identifying a custom call generator.
// or Smi identifying a builtin function.
// In the long run we don't want all functions to have this field but
// we can fix that when we have a better model for storing hidden data
// on objects.
@ -3880,8 +3905,9 @@ class SharedFunctionInfo: public HeapObject {
inline bool IsApiFunction();
inline FunctionTemplateInfo* get_api_func_data();
inline bool HasCustomCallGenerator();
inline int custom_call_generator_id();
inline bool HasBuiltinFunctionId();
inline bool IsBuiltinMathFunction();
inline BuiltinFunctionId builtin_function_id();
// [script info]: Script from which the function originates.
DECL_ACCESSORS(script, Object)
@ -4132,12 +4158,6 @@ class SharedFunctionInfo: public HeapObject {
static const int kAlignedSize = POINTER_SIZE_ALIGN(kSize);
// Get/set a special tag on the functions from math.js so we can inline
// efficient versions of them in the code.
inline MathFunctionId math_function_id();
inline void set_math_function_id(int id);
static inline int max_math_id_number() { return kMathFunctionMask; }
typedef FixedBodyDescriptor<kNameOffset,
kThisPropertyAssignmentsOffset + kPointerSize,
kSize> BodyDescriptor;
@ -4155,12 +4175,10 @@ class SharedFunctionInfo: public HeapObject {
static const int kHasOnlySimpleThisPropertyAssignments = 0;
static const int kTryFullCodegen = 1;
static const int kAllowLazyCompilation = 2;
static const int kMathFunctionShift = 3;
static const int kMathFunctionMask = 0x1f;
static const int kLiveObjectsMayExist = 8;
static const int kCodeAgeShift = 9;
static const int kLiveObjectsMayExist = 3;
static const int kCodeAgeShift = 4;
static const int kCodeAgeMask = 0x7;
static const int kOptimizationDisabled = 12;
static const int kOptimizationDisabled = 7;
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
};

View File

@ -614,22 +614,6 @@ static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
}
// Sets the magic number that identifies a function as one of the special
// math functions that can be inlined.
static MaybeObject* Runtime_SetMathFunctionId(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
CONVERT_CHECKED(JSFunction, function, args[0]);
CONVERT_CHECKED(Smi, id, args[1]);
RUNTIME_ASSERT(id->value() >= 0);
RUNTIME_ASSERT(id->value() < SharedFunctionInfo::max_math_id_number());
function->shared()->set_math_function_id(id->value());
return Heap::undefined_value();
}
static MaybeObject* Runtime_IsConstructCall(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 0);

View File

@ -66,7 +66,6 @@ namespace internal {
\
F(IsInPrototypeChain, 2, 1) \
F(SetHiddenPrototype, 2, 1) \
F(SetMathFunctionId, 2, 1) \
\
F(IsConstructCall, 0, 1) \
\

View File

@ -1501,25 +1501,31 @@ CallStubCompiler::CallStubCompiler(int argc,
}
MaybeObject* CallStubCompiler::CompileCustomCall(int generator_id,
bool CallStubCompiler::HasCustomCallGenerator(BuiltinFunctionId id) {
#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
#undef CALL_GENERATOR_CASE
return false;
}
MaybeObject* CallStubCompiler::CompileCustomCall(BuiltinFunctionId id,
Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* fname) {
ASSERT(generator_id >= 0 && generator_id < kNumCallGenerators);
switch (generator_id) {
#define CALL_GENERATOR_CASE(ignored1, ignored2, name) \
case k##name##CallGenerator: \
return CallStubCompiler::Compile##name##Call(object, \
holder, \
cell, \
function, \
fname);
CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
#undef CALL_GENERATOR_CASE
#define CALL_GENERATOR_CASE(name) \
if (id == k##name) { \
return CallStubCompiler::Compile##name##Call(object, \
holder, \
cell, \
function, \
fname); \
}
UNREACHABLE();
CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
#undef CALL_GENERATOR_CASE
ASSERT(!HasCustomCallGenerator(id));
return Heap::undefined_value();
}

View File

@ -643,37 +643,20 @@ class KeyedStoreStubCompiler: public StubCompiler {
};
// List of functions with custom constant call IC stubs.
//
// Installation of custom call generators for the selected builtins is
// handled by the bootstrapper.
//
// Each entry has a name of a global object property holding an object
// optionally followed by ".prototype" (this controls whether the
// generator is set on the object itself or, in case it's a function,
// on the its instance prototype), a name of a builtin function on the
// object (the one the generator is set for), and a name of the
// generator (used to build ids and generator function names).
#define CUSTOM_CALL_IC_GENERATORS(V) \
V(Array.prototype, push, ArrayPush) \
V(Array.prototype, pop, ArrayPop) \
V(String.prototype, charCodeAt, StringCharCodeAt) \
V(String.prototype, charAt, StringCharAt) \
V(String, fromCharCode, StringFromCharCode) \
V(Math, floor, MathFloor) \
V(Math, abs, MathAbs)
// Subset of FUNCTIONS_WITH_ID_LIST with custom constant/global call
// IC stubs.
#define CUSTOM_CALL_IC_GENERATORS(V) \
V(ArrayPush) \
V(ArrayPop) \
V(StringCharCodeAt) \
V(StringCharAt) \
V(StringFromCharCode) \
V(MathFloor) \
V(MathAbs)
class CallStubCompiler: public StubCompiler {
public:
enum {
#define DECLARE_CALL_GENERATOR_ID(ignored1, ignore2, name) \
k##name##CallGenerator,
CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR_ID)
#undef DECLARE_CALL_GENERATOR_ID
kNumCallGenerators
};
CallStubCompiler(int argc,
InLoopFlag in_loop,
Code::Kind kind,
@ -697,16 +680,20 @@ class CallStubCompiler: public StubCompiler {
JSFunction* function,
String* name);
// Compiles a custom call constant/global IC using the generator
// with given id. For constant calls cell is NULL.
MUST_USE_RESULT MaybeObject* CompileCustomCall(int generator_id,
static bool HasCustomCallGenerator(BuiltinFunctionId id);
private:
// Compiles a custom call constant/global IC. For constant calls
// cell is NULL. Returns undefined if there is no custom call code
// for the given function or it can't be generated.
MUST_USE_RESULT MaybeObject* CompileCustomCall(BuiltinFunctionId id,
Object* object,
JSObject* holder,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name);
#define DECLARE_CALL_GENERATOR(ignored1, ignored2, name) \
#define DECLARE_CALL_GENERATOR(name) \
MUST_USE_RESULT MaybeObject* Compile##name##Call(Object* object, \
JSObject* holder, \
JSGlobalPropertyCell* cell, \
@ -715,7 +702,6 @@ class CallStubCompiler: public StubCompiler {
CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR)
#undef DECLARE_CALL_GENERATOR
private:
const ParameterCount arguments_;
const InLoopFlag in_loop_;
const Code::Kind kind_;

View File

@ -948,8 +948,8 @@ MaybeObject* CallStubCompiler::CompileCallConstant(Object* object,
// -----------------------------------
SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id();
if (function_info->HasBuiltinFunctionId()) {
BuiltinFunctionId id = function_info->builtin_function_id();
MaybeObject* maybe_result = CompileCustomCall(
id, object, holder, NULL, function, name);
Object* result;
@ -1830,8 +1830,8 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
// -----------------------------------
SharedFunctionInfo* function_info = function->shared();
if (function_info->HasCustomCallGenerator()) {
const int id = function_info->custom_call_generator_id();
if (function_info->HasBuiltinFunctionId()) {
BuiltinFunctionId id = function_info->builtin_function_id();
MaybeObject* maybe_result = CompileCustomCall(
id, object, holder, cell, function, name);
Object* result;