Reland "Load global object and builtins from activation."

Reland fixes:
Don't set string flags (doing so leaks memory).

Load closure from activation for building literals.

R=titzer@chromium.org

Review URL: https://codereview.chromium.org/484273003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23275 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
sigurds@chromium.org 2014-08-21 12:40:10 +00:00
parent 22d5ceb1f2
commit dd3c097123
6 changed files with 91 additions and 29 deletions

View File

@ -6,6 +6,7 @@
#include "src/compiler.h" #include "src/compiler.h"
#include "src/compiler/control-builders.h" #include "src/compiler/control-builders.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/node-properties.h" #include "src/compiler/node-properties.h"
#include "src/compiler/node-properties-inl.h" #include "src/compiler/node-properties-inl.h"
#include "src/full-codegen.h" #include "src/full-codegen.h"
@ -701,13 +702,12 @@ void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
test_should_filter.If(should_filter_cond); test_should_filter.If(should_filter_cond);
test_should_filter.Then(); test_should_filter.Then();
value = environment()->Pop(); value = environment()->Pop();
// TODO(dcarney): Better load from function context. Node* builtins = BuildLoadBuiltinsObject();
// See comment in BuildLoadBuiltinsObject. Node* function = BuildLoadObjectField(
Handle<JSFunction> function(JSFunction::cast( builtins,
info()->context()->builtins()->javascript_builtin( JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::FILTER_KEY));
Builtins::FILTER_KEY)));
// Callee. // Callee.
environment()->Push(jsgraph()->HeapConstant(function)); environment()->Push(function);
// Receiver. // Receiver.
environment()->Push(obj); environment()->Push(obj);
// Args. // Args.
@ -840,10 +840,11 @@ void AstGraphBuilder::VisitLiteral(Literal* expr) {
void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
Handle<JSFunction> closure = info()->closure(); Node* closure = GetFunctionClosure();
// Create node to materialize a regular expression literal. // Create node to materialize a regular expression literal.
Node* literals_array = jsgraph()->Constant(handle(closure->literals())); Node* literals_array =
BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* literal_index = jsgraph()->Constant(expr->literal_index()); Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* pattern = jsgraph()->Constant(expr->pattern()); Node* pattern = jsgraph()->Constant(expr->pattern());
Node* flags = jsgraph()->Constant(expr->flags()); Node* flags = jsgraph()->Constant(expr->flags());
@ -854,11 +855,12 @@ void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
Handle<JSFunction> closure = info()->closure(); Node* closure = GetFunctionClosure();
// Create node to deep-copy the literal boilerplate. // Create node to deep-copy the literal boilerplate.
expr->BuildConstantProperties(isolate()); expr->BuildConstantProperties(isolate());
Node* literals_array = jsgraph()->Constant(handle(closure->literals())); Node* literals_array =
BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* literal_index = jsgraph()->Constant(expr->literal_index()); Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* constants = jsgraph()->Constant(expr->constant_properties()); Node* constants = jsgraph()->Constant(expr->constant_properties());
Node* flags = jsgraph()->Constant(expr->ComputeFlags()); Node* flags = jsgraph()->Constant(expr->ComputeFlags());
@ -963,11 +965,12 @@ void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
Handle<JSFunction> closure = info()->closure(); Node* closure = GetFunctionClosure();
// Create node to deep-copy the literal boilerplate. // Create node to deep-copy the literal boilerplate.
expr->BuildConstantElements(isolate()); expr->BuildConstantElements(isolate());
Node* literals_array = jsgraph()->Constant(handle(closure->literals())); Node* literals_array =
BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
Node* literal_index = jsgraph()->Constant(expr->literal_index()); Node* literal_index = jsgraph()->Constant(expr->literal_index());
Node* constants = jsgraph()->Constant(expr->constant_elements()); Node* constants = jsgraph()->Constant(expr->constant_elements());
Node* flags = jsgraph()->Constant(expr->ComputeFlags()); Node* flags = jsgraph()->Constant(expr->ComputeFlags());
@ -1908,25 +1911,28 @@ Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
} }
Node* AstGraphBuilder::BuildLoadObjectField(Node* object, int offset) {
// TODO(sigurds) Use simplified load here once it is ready.
MachineOperatorBuilder machine(zone());
Node* field_load = NewNode(machine.Load(kMachAnyTagged), object,
jsgraph_->Int32Constant(offset - kHeapObjectTag));
return field_load;
}
Node* AstGraphBuilder::BuildLoadBuiltinsObject() { Node* AstGraphBuilder::BuildLoadBuiltinsObject() {
// TODO(mstarzinger): Better load from function context, otherwise optimized Node* global = BuildLoadGlobalObject();
// code cannot be shared across native contexts. Node* builtins =
return jsgraph()->Constant(handle(info()->context()->builtins())); BuildLoadObjectField(global, JSGlobalObject::kBuiltinsOffset);
return builtins;
} }
Node* AstGraphBuilder::BuildLoadGlobalObject() { Node* AstGraphBuilder::BuildLoadGlobalObject() {
#if 0
Node* context = GetFunctionContext(); Node* context = GetFunctionContext();
// TODO(mstarzinger): Use mid-level operator on FixedArray instead of the Operator* load_op =
// JS-level operator that targets JSObject. javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true);
Node* index = jsgraph()->Constant(Context::GLOBAL_OBJECT_INDEX); return NewNode(load_op, context);
return NewNode(javascript()->LoadProperty(), context, index);
#else
// TODO(mstarzinger): Better load from function context, otherwise optimized
// code cannot be shared across native contexts. See unused code above.
return jsgraph()->Constant(handle(info()->context()->global_object()));
#endif
} }

View File

@ -88,6 +88,7 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
Node* BuildLoadBuiltinsObject(); Node* BuildLoadBuiltinsObject();
Node* BuildLoadGlobalObject(); Node* BuildLoadGlobalObject();
Node* BuildLoadClosure(); Node* BuildLoadClosure();
Node* BuildLoadObjectField(Node* object, int offset);
// Builders for automatic type conversion. // Builders for automatic type conversion.
Node* BuildToBoolean(Node* value); Node* BuildToBoolean(Node* value);

View File

@ -186,7 +186,7 @@ Handle<Code> Pipeline::GenerateCode() {
VerifyAndPrintGraph(&graph, "Initial untyped"); VerifyAndPrintGraph(&graph, "Initial untyped");
if (FLAG_context_specialization) { if (context_specialization_) {
SourcePositionTable::Scope pos(&source_positions, SourcePositionTable::Scope pos(&source_positions,
SourcePosition::Unknown()); SourcePosition::Unknown());
// Specialize the code to the context as aggressively as possible. // Specialize the code to the context as aggressively as possible.

View File

@ -24,7 +24,8 @@ class Linkage;
class Pipeline { class Pipeline {
public: public:
explicit Pipeline(CompilationInfo* info) : info_(info) {} explicit Pipeline(CompilationInfo* info)
: info_(info), context_specialization_(FLAG_context_specialization) {}
// Run the entire pipeline and generate a handle to a code object. // Run the entire pipeline and generate a handle to a code object.
Handle<Code> GenerateCode(); Handle<Code> GenerateCode();
@ -39,9 +40,14 @@ class Pipeline {
static void SetUp(); static void SetUp();
static void TearDown(); static void TearDown();
bool context_specialization() { return context_specialization_; }
void set_context_specialization(bool context_specialization) {
context_specialization_ = context_specialization;
}
private: private:
CompilationInfo* info_; CompilationInfo* info_;
bool context_specialization_;
CompilationInfo* info() const { return info_; } CompilationInfo* info() const { return info_; }
Isolate* isolate() { return info_->isolate(); } Isolate* isolate() { return info_->isolate(); }

View File

@ -26,10 +26,13 @@ namespace compiler {
class FunctionTester : public InitializedHandleScope { class FunctionTester : public InitializedHandleScope {
public: public:
explicit FunctionTester(const char* source) explicit FunctionTester(const char* source, bool context_specialization =
FLAG_context_specialization)
: isolate(main_isolate()), : isolate(main_isolate()),
function((FLAG_allow_natives_syntax = true, NewFunction(source))) { function((FLAG_allow_natives_syntax = true, NewFunction(source))),
context_specialization_(context_specialization) {
Compile(function); Compile(function);
USE(context_specialization_);
} }
Isolate* isolate; Isolate* isolate;
@ -52,6 +55,7 @@ class FunctionTester : public InitializedHandleScope {
EnsureDeoptimizationSupport(&info); EnsureDeoptimizationSupport(&info);
Pipeline pipeline(&info); Pipeline pipeline(&info);
pipeline.set_context_specialization(context_specialization_);
Handle<Code> code = pipeline.GenerateCode(); Handle<Code> code = pipeline.GenerateCode();
CHECK(!code.is_null()); CHECK(!code.is_null());
@ -188,6 +192,9 @@ class FunctionTester : public InitializedHandleScope {
Handle<Object> true_value() { return isolate->factory()->true_value(); } Handle<Object> true_value() { return isolate->factory()->true_value(); }
Handle<Object> false_value() { return isolate->factory()->false_value(); } Handle<Object> false_value() { return isolate->factory()->false_value(); }
private:
bool context_specialization_;
}; };
} }
} }

View File

@ -245,3 +245,45 @@ TEST(CallEval) {
T.CheckCall(T.Val(42), T.Val("x"), T.undefined()); T.CheckCall(T.Val(42), T.Val("x"), T.undefined());
} }
TEST(ContextLoadedFromActivation) {
const char* script =
"var x = 42;"
"(function() {"
" return function () { return x };"
"})()";
// Disable context specialization.
FunctionTester T(script, false);
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
v8::Context::Scope scope(context);
v8::Local<v8::Value> value = CompileRun(script);
i::Handle<i::Object> ofun = v8::Utils::OpenHandle(*value);
i::Handle<i::JSFunction> jsfun = Handle<JSFunction>::cast(ofun);
jsfun->set_code(T.function->code());
context->Global()->Set(v8_str("foo"), v8::Utils::ToLocal(jsfun));
CompileRun("var x = 24;");
ExpectInt32("foo();", 24);
}
TEST(BuiltinLoadedFromActivation) {
const char* script =
"var x = 42;"
"(function() {"
" return function () { return this; };"
"})()";
// Disable context specialization.
FunctionTester T(script, false);
v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
v8::Context::Scope scope(context);
v8::Local<v8::Value> value = CompileRun(script);
i::Handle<i::Object> ofun = v8::Utils::OpenHandle(*value);
i::Handle<i::JSFunction> jsfun = Handle<JSFunction>::cast(ofun);
jsfun->set_code(T.function->code());
context->Global()->Set(v8_str("foo"), v8::Utils::ToLocal(jsfun));
CompileRun("var x = 24;");
ExpectObject("foo()", context->Global());
}