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:
parent
22d5ceb1f2
commit
dd3c097123
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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.
|
||||||
|
@ -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(); }
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user