Split even more runtime functions into separate files.
R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/612023002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24307 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
aee775a509
commit
381616fb70
4
BUILD.gn
4
BUILD.gn
@ -827,7 +827,11 @@ source_set("v8_base") {
|
||||
"src/runtime/runtime-collections.cc",
|
||||
"src/runtime/runtime-compiler.cc",
|
||||
"src/runtime/runtime-i18n.cc",
|
||||
"src/runtime/runtime-date.cc",
|
||||
"src/runtime/runtime-debug.cc",
|
||||
"src/runtime/runtime-generator.cc",
|
||||
"src/runtime/runtime-json.cc",
|
||||
"src/runtime/runtime-liveedit.cc",
|
||||
"src/runtime/runtime-maths.cc",
|
||||
"src/runtime/runtime-numbers.cc",
|
||||
"src/runtime/runtime-regexp.cc",
|
||||
|
@ -454,6 +454,10 @@ class Debug {
|
||||
// Record function from which eval was called.
|
||||
static void RecordEvalCaller(Handle<Script> script);
|
||||
|
||||
bool CheckExecutionState(int id) {
|
||||
return !debug_context().is_null() && break_id() != 0 && break_id() == id;
|
||||
}
|
||||
|
||||
// Flags and states.
|
||||
DebugScope* debugger_entry() { return thread_local_.current_debug_scope_; }
|
||||
inline Handle<Context> debug_context() { return debug_context_; }
|
||||
|
@ -1121,6 +1121,19 @@ MaybeHandle<Object> Object::GetElement(Isolate* isolate,
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> Object::GetPrototypeSkipHiddenPrototypes(
|
||||
Isolate* isolate, Handle<Object> receiver) {
|
||||
PrototypeIterator iter(isolate, receiver);
|
||||
while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
|
||||
if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
|
||||
return PrototypeIterator::GetCurrent(iter);
|
||||
}
|
||||
iter.Advance();
|
||||
}
|
||||
return PrototypeIterator::GetCurrent(iter);
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Object> Object::GetPropertyOrElement(Handle<Object> object,
|
||||
Handle<Name> name) {
|
||||
uint32_t index;
|
||||
|
@ -1167,6 +1167,9 @@ class Object {
|
||||
Handle<Object> receiver,
|
||||
uint32_t index);
|
||||
|
||||
static inline Handle<Object> GetPrototypeSkipHiddenPrototypes(
|
||||
Isolate* isolate, Handle<Object> receiver);
|
||||
|
||||
// Returns the permanent hash code associated with this object. May return
|
||||
// undefined if not yet created.
|
||||
Object* GetHash();
|
||||
|
@ -9,12 +9,10 @@
|
||||
#include "src/deoptimizer.h"
|
||||
#include "src/frames.h"
|
||||
#include "src/full-codegen.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/isolate-inl.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
#include "src/v8threads.h"
|
||||
#include "src/vm-state.h"
|
||||
#include "src/vm-state-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
|
190
src/runtime/runtime-date.cc
Normal file
190
src/runtime/runtime-date.cc
Normal file
@ -0,0 +1,190 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/arguments.h"
|
||||
#include "src/date.h"
|
||||
#include "src/dateparser-inl.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DateMakeDay) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 2);
|
||||
|
||||
CONVERT_SMI_ARG_CHECKED(year, 0);
|
||||
CONVERT_SMI_ARG_CHECKED(month, 1);
|
||||
|
||||
int days = isolate->date_cache()->DaysFromYearMonth(year, month);
|
||||
RUNTIME_ASSERT(Smi::IsValid(days));
|
||||
return Smi::FromInt(days);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DateSetValue) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
|
||||
CONVERT_DOUBLE_ARG_CHECKED(time, 1);
|
||||
CONVERT_SMI_ARG_CHECKED(is_utc, 2);
|
||||
|
||||
DateCache* date_cache = isolate->date_cache();
|
||||
|
||||
Handle<Object> value;
|
||||
;
|
||||
bool is_value_nan = false;
|
||||
if (std::isnan(time)) {
|
||||
value = isolate->factory()->nan_value();
|
||||
is_value_nan = true;
|
||||
} else if (!is_utc && (time < -DateCache::kMaxTimeBeforeUTCInMs ||
|
||||
time > DateCache::kMaxTimeBeforeUTCInMs)) {
|
||||
value = isolate->factory()->nan_value();
|
||||
is_value_nan = true;
|
||||
} else {
|
||||
time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
|
||||
if (time < -DateCache::kMaxTimeInMs || time > DateCache::kMaxTimeInMs) {
|
||||
value = isolate->factory()->nan_value();
|
||||
is_value_nan = true;
|
||||
} else {
|
||||
value = isolate->factory()->NewNumber(DoubleToInteger(time));
|
||||
}
|
||||
}
|
||||
date->SetValue(*value, is_value_nan);
|
||||
return *value;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowNotDateError) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError("not_date_object", HandleVector<Object>(NULL, 0)));
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DateCurrentTime) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
if (FLAG_log_timer_events) LOG(isolate, CurrentTimeEvent());
|
||||
|
||||
// According to ECMA-262, section 15.9.1, page 117, the precision of
|
||||
// the number in a Date object representing a particular instant in
|
||||
// time is milliseconds. Therefore, we floor the result of getting
|
||||
// the OS time.
|
||||
double millis;
|
||||
if (FLAG_verify_predictable) {
|
||||
millis = 1388534400000.0; // Jan 1 2014 00:00:00 GMT+0000
|
||||
millis += Floor(isolate->heap()->synthetic_time());
|
||||
} else {
|
||||
millis = Floor(base::OS::TimeCurrentMillis());
|
||||
}
|
||||
return *isolate->factory()->NewNumber(millis);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DateParseString) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
|
||||
|
||||
RUNTIME_ASSERT(output->HasFastElements());
|
||||
JSObject::EnsureCanContainHeapObjectElements(output);
|
||||
RUNTIME_ASSERT(output->HasFastObjectElements());
|
||||
Handle<FixedArray> output_array(FixedArray::cast(output->elements()));
|
||||
RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
|
||||
|
||||
str = String::Flatten(str);
|
||||
DisallowHeapAllocation no_gc;
|
||||
|
||||
bool result;
|
||||
String::FlatContent str_content = str->GetFlatContent();
|
||||
if (str_content.IsOneByte()) {
|
||||
result = DateParser::Parse(str_content.ToOneByteVector(), *output_array,
|
||||
isolate->unicode_cache());
|
||||
} else {
|
||||
DCHECK(str_content.IsTwoByte());
|
||||
result = DateParser::Parse(str_content.ToUC16Vector(), *output_array,
|
||||
isolate->unicode_cache());
|
||||
}
|
||||
|
||||
if (result) {
|
||||
return *output;
|
||||
} else {
|
||||
return isolate->heap()->null_value();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DateLocalTimezone) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
|
||||
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
|
||||
RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs &&
|
||||
x <= DateCache::kMaxTimeBeforeUTCInMs);
|
||||
const char* zone =
|
||||
isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x));
|
||||
Handle<String> result =
|
||||
isolate->factory()->NewStringFromUtf8(CStrVector(zone)).ToHandleChecked();
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DateToUTC) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
|
||||
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
|
||||
RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs &&
|
||||
x <= DateCache::kMaxTimeBeforeUTCInMs);
|
||||
int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
|
||||
|
||||
return *isolate->factory()->NewNumber(static_cast<double>(time));
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
|
||||
HandleScope hs(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
if (!isolate->eternal_handles()->Exists(EternalHandles::DATE_CACHE_VERSION)) {
|
||||
Handle<FixedArray> date_cache_version =
|
||||
isolate->factory()->NewFixedArray(1, TENURED);
|
||||
date_cache_version->set(0, Smi::FromInt(0));
|
||||
isolate->eternal_handles()->CreateSingleton(
|
||||
isolate, *date_cache_version, EternalHandles::DATE_CACHE_VERSION);
|
||||
}
|
||||
Handle<FixedArray> date_cache_version =
|
||||
Handle<FixedArray>::cast(isolate->eternal_handles()->GetSingleton(
|
||||
EternalHandles::DATE_CACHE_VERSION));
|
||||
// Return result as a JS array.
|
||||
Handle<JSObject> result =
|
||||
isolate->factory()->NewJSObject(isolate->array_function());
|
||||
JSArray::SetContent(Handle<JSArray>::cast(result), date_cache_version);
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(RuntimeReference_DateField) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_ARG_CHECKED(Object, obj, 0);
|
||||
CONVERT_SMI_ARG_CHECKED(index, 1);
|
||||
if (!obj->IsJSDate()) {
|
||||
HandleScope scope(isolate);
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate,
|
||||
NewTypeError("not_date_object", HandleVector<Object>(NULL, 0)));
|
||||
}
|
||||
JSDate* date = JSDate::cast(obj);
|
||||
if (index == 0) return date->value();
|
||||
return JSDate::GetField(date, Smi::FromInt(index));
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal
|
2736
src/runtime/runtime-debug.cc
Normal file
2736
src/runtime/runtime-debug.cc
Normal file
File diff suppressed because it is too large
Load Diff
230
src/runtime/runtime-generator.cc
Normal file
230
src/runtime/runtime-generator.cc
Normal file
@ -0,0 +1,230 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/arguments.h"
|
||||
#include "src/frames-inl.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_CreateJSGeneratorObject) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
|
||||
JavaScriptFrameIterator it(isolate);
|
||||
JavaScriptFrame* frame = it.frame();
|
||||
Handle<JSFunction> function(frame->function());
|
||||
RUNTIME_ASSERT(function->shared()->is_generator());
|
||||
|
||||
Handle<JSGeneratorObject> generator;
|
||||
if (frame->IsConstructor()) {
|
||||
generator = handle(JSGeneratorObject::cast(frame->receiver()));
|
||||
} else {
|
||||
generator = isolate->factory()->NewJSGeneratorObject(function);
|
||||
}
|
||||
generator->set_function(*function);
|
||||
generator->set_context(Context::cast(frame->context()));
|
||||
generator->set_receiver(frame->receiver());
|
||||
generator->set_continuation(0);
|
||||
generator->set_operand_stack(isolate->heap()->empty_fixed_array());
|
||||
generator->set_stack_handler_index(-1);
|
||||
|
||||
return *generator;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_SuspendJSGeneratorObject) {
|
||||
HandleScope handle_scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator_object, 0);
|
||||
|
||||
JavaScriptFrameIterator stack_iterator(isolate);
|
||||
JavaScriptFrame* frame = stack_iterator.frame();
|
||||
RUNTIME_ASSERT(frame->function()->shared()->is_generator());
|
||||
DCHECK_EQ(frame->function(), generator_object->function());
|
||||
|
||||
// The caller should have saved the context and continuation already.
|
||||
DCHECK_EQ(generator_object->context(), Context::cast(frame->context()));
|
||||
DCHECK_LT(0, generator_object->continuation());
|
||||
|
||||
// We expect there to be at least two values on the operand stack: the return
|
||||
// value of the yield expression, and the argument to this runtime call.
|
||||
// Neither of those should be saved.
|
||||
int operands_count = frame->ComputeOperandsCount();
|
||||
DCHECK_GE(operands_count, 2);
|
||||
operands_count -= 2;
|
||||
|
||||
if (operands_count == 0) {
|
||||
// Although it's semantically harmless to call this function with an
|
||||
// operands_count of zero, it is also unnecessary.
|
||||
DCHECK_EQ(generator_object->operand_stack(),
|
||||
isolate->heap()->empty_fixed_array());
|
||||
DCHECK_EQ(generator_object->stack_handler_index(), -1);
|
||||
// If there are no operands on the stack, there shouldn't be a handler
|
||||
// active either.
|
||||
DCHECK(!frame->HasHandler());
|
||||
} else {
|
||||
int stack_handler_index = -1;
|
||||
Handle<FixedArray> operand_stack =
|
||||
isolate->factory()->NewFixedArray(operands_count);
|
||||
frame->SaveOperandStack(*operand_stack, &stack_handler_index);
|
||||
generator_object->set_operand_stack(*operand_stack);
|
||||
generator_object->set_stack_handler_index(stack_handler_index);
|
||||
}
|
||||
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
// Note that this function is the slow path for resuming generators. It is only
|
||||
// called if the suspended activation had operands on the stack, stack handlers
|
||||
// needing rewinding, or if the resume should throw an exception. The fast path
|
||||
// is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
|
||||
// inlined into GeneratorNext and GeneratorThrow. EmitGeneratorResumeResume is
|
||||
// called in any case, as it needs to reconstruct the stack frame and make space
|
||||
// for arguments and operands.
|
||||
RUNTIME_FUNCTION(Runtime_ResumeJSGeneratorObject) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 3);
|
||||
CONVERT_ARG_CHECKED(JSGeneratorObject, generator_object, 0);
|
||||
CONVERT_ARG_CHECKED(Object, value, 1);
|
||||
CONVERT_SMI_ARG_CHECKED(resume_mode_int, 2);
|
||||
JavaScriptFrameIterator stack_iterator(isolate);
|
||||
JavaScriptFrame* frame = stack_iterator.frame();
|
||||
|
||||
DCHECK_EQ(frame->function(), generator_object->function());
|
||||
DCHECK(frame->function()->is_compiled());
|
||||
|
||||
STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
|
||||
STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
|
||||
|
||||
Address pc = generator_object->function()->code()->instruction_start();
|
||||
int offset = generator_object->continuation();
|
||||
DCHECK(offset > 0);
|
||||
frame->set_pc(pc + offset);
|
||||
if (FLAG_enable_ool_constant_pool) {
|
||||
frame->set_constant_pool(
|
||||
generator_object->function()->code()->constant_pool());
|
||||
}
|
||||
generator_object->set_continuation(JSGeneratorObject::kGeneratorExecuting);
|
||||
|
||||
FixedArray* operand_stack = generator_object->operand_stack();
|
||||
int operands_count = operand_stack->length();
|
||||
if (operands_count != 0) {
|
||||
frame->RestoreOperandStack(operand_stack,
|
||||
generator_object->stack_handler_index());
|
||||
generator_object->set_operand_stack(isolate->heap()->empty_fixed_array());
|
||||
generator_object->set_stack_handler_index(-1);
|
||||
}
|
||||
|
||||
JSGeneratorObject::ResumeMode resume_mode =
|
||||
static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
|
||||
switch (resume_mode) {
|
||||
case JSGeneratorObject::NEXT:
|
||||
return value;
|
||||
case JSGeneratorObject::THROW:
|
||||
return isolate->Throw(value);
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return isolate->ThrowIllegalOperation();
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ThrowGeneratorStateError) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
int continuation = generator->continuation();
|
||||
const char* message = continuation == JSGeneratorObject::kGeneratorClosed
|
||||
? "generator_finished"
|
||||
: "generator_running";
|
||||
Vector<Handle<Object> > argv = HandleVector<Object>(NULL, 0);
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewError(message, argv));
|
||||
}
|
||||
|
||||
|
||||
// Returns function of generator activation.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
return generator->function();
|
||||
}
|
||||
|
||||
|
||||
// Returns context of generator activation.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetContext) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
return generator->context();
|
||||
}
|
||||
|
||||
|
||||
// Returns receiver of generator activation.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
return generator->receiver();
|
||||
}
|
||||
|
||||
|
||||
// Returns generator continuation as a PC offset, or the magic -1 or 0 values.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
return Smi::FromInt(generator->continuation());
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
if (generator->is_suspended()) {
|
||||
Handle<Code> code(generator->function()->code(), isolate);
|
||||
int offset = generator->continuation();
|
||||
|
||||
RUNTIME_ASSERT(0 <= offset && offset < code->Size());
|
||||
Address pc = code->address() + offset;
|
||||
|
||||
return Smi::FromInt(code->SourcePosition(pc));
|
||||
}
|
||||
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_FunctionIsGenerator) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_CHECKED(JSFunction, f, 0);
|
||||
return isolate->heap()->ToBoolean(f->shared()->is_generator());
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(RuntimeReference_GeneratorNext) {
|
||||
UNREACHABLE(); // Optimization disabled in SetUpGenerators().
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(RuntimeReference_GeneratorThrow) {
|
||||
UNREACHABLE(); // Optimization disabled in SetUpGenerators().
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal
|
293
src/runtime/runtime-liveedit.cc
Normal file
293
src/runtime/runtime-liveedit.cc
Normal file
@ -0,0 +1,293 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/arguments.h"
|
||||
#include "src/debug.h"
|
||||
#include "src/liveedit.h"
|
||||
#include "src/runtime/runtime.h"
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
|
||||
Script* script,
|
||||
FixedArray* buffer) {
|
||||
DisallowHeapAllocation no_allocation;
|
||||
int counter = 0;
|
||||
int buffer_size = buffer->length();
|
||||
for (HeapObject* obj = iterator->next(); obj != NULL;
|
||||
obj = iterator->next()) {
|
||||
DCHECK(obj != NULL);
|
||||
if (!obj->IsSharedFunctionInfo()) {
|
||||
continue;
|
||||
}
|
||||
SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
|
||||
if (shared->script() != script) {
|
||||
continue;
|
||||
}
|
||||
if (counter < buffer_size) {
|
||||
buffer->set(counter, shared);
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
// For a script finds all SharedFunctionInfo's in the heap that points
|
||||
// to this script. Returns JSArray of SharedFunctionInfo wrapped
|
||||
// in OpaqueReferences.
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditFindSharedFunctionInfosForScript) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_CHECKED(JSValue, script_value, 0);
|
||||
|
||||
RUNTIME_ASSERT(script_value->value()->IsScript());
|
||||
Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
|
||||
|
||||
const int kBufferSize = 32;
|
||||
|
||||
Handle<FixedArray> array;
|
||||
array = isolate->factory()->NewFixedArray(kBufferSize);
|
||||
int number;
|
||||
Heap* heap = isolate->heap();
|
||||
{
|
||||
HeapIterator heap_iterator(heap);
|
||||
Script* scr = *script;
|
||||
FixedArray* arr = *array;
|
||||
number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
|
||||
}
|
||||
if (number > kBufferSize) {
|
||||
array = isolate->factory()->NewFixedArray(number);
|
||||
HeapIterator heap_iterator(heap);
|
||||
Script* scr = *script;
|
||||
FixedArray* arr = *array;
|
||||
FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
|
||||
}
|
||||
|
||||
Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
|
||||
result->set_length(Smi::FromInt(number));
|
||||
|
||||
LiveEdit::WrapSharedFunctionInfos(result);
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
// For a script calculates compilation information about all its functions.
|
||||
// The script source is explicitly specified by the second argument.
|
||||
// The source of the actual script is not used, however it is important that
|
||||
// all generated code keeps references to this particular instance of script.
|
||||
// Returns a JSArray of compilation infos. The array is ordered so that
|
||||
// each function with all its descendant is always stored in a continues range
|
||||
// with the function itself going first. The root function is a script function.
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditGatherCompileInfo) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_ARG_CHECKED(JSValue, script, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
|
||||
|
||||
RUNTIME_ASSERT(script->value()->IsScript());
|
||||
Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
|
||||
|
||||
Handle<JSArray> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result, LiveEdit::GatherCompileInfo(script_handle, source));
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
// Changes the source of the script to a new_source.
|
||||
// If old_script_name is provided (i.e. is a String), also creates a copy of
|
||||
// the script with its original source and sends notification to debugger.
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditReplaceScript) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 3);
|
||||
CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, old_script_name, 2);
|
||||
|
||||
RUNTIME_ASSERT(original_script_value->value()->IsScript());
|
||||
Handle<Script> original_script(Script::cast(original_script_value->value()));
|
||||
|
||||
Handle<Object> old_script = LiveEdit::ChangeScriptSource(
|
||||
original_script, new_source, old_script_name);
|
||||
|
||||
if (old_script->IsScript()) {
|
||||
Handle<Script> script_handle = Handle<Script>::cast(old_script);
|
||||
return *Script::GetWrapper(script_handle);
|
||||
} else {
|
||||
return isolate->heap()->null_value();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditFunctionSourceUpdated) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
|
||||
RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
|
||||
|
||||
LiveEdit::FunctionSourceUpdated(shared_info);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
// Replaces code of SharedFunctionInfo with a new one.
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditReplaceFunctionCode) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
|
||||
RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_info));
|
||||
|
||||
LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
// Connects SharedFunctionInfo to another script.
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditFunctionSetScript) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, function_object, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, script_object, 1);
|
||||
|
||||
if (function_object->IsJSValue()) {
|
||||
Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
|
||||
if (script_object->IsJSValue()) {
|
||||
RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
|
||||
Script* script = Script::cast(JSValue::cast(*script_object)->value());
|
||||
script_object = Handle<Object>(script, isolate);
|
||||
}
|
||||
RUNTIME_ASSERT(function_wrapper->value()->IsSharedFunctionInfo());
|
||||
LiveEdit::SetFunctionScript(function_wrapper, script_object);
|
||||
} else {
|
||||
// Just ignore this. We may not have a SharedFunctionInfo for some functions
|
||||
// and we check it in this function.
|
||||
}
|
||||
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
// In a code of a parent function replaces original function as embedded object
|
||||
// with a substitution one.
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditReplaceRefToNestedFunction) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 3);
|
||||
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
|
||||
RUNTIME_ASSERT(parent_wrapper->value()->IsSharedFunctionInfo());
|
||||
RUNTIME_ASSERT(orig_wrapper->value()->IsSharedFunctionInfo());
|
||||
RUNTIME_ASSERT(subst_wrapper->value()->IsSharedFunctionInfo());
|
||||
|
||||
LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
|
||||
subst_wrapper);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
// Updates positions of a shared function info (first parameter) according
|
||||
// to script source change. Text change is described in second parameter as
|
||||
// array of groups of 3 numbers:
|
||||
// (change_begin, change_end, change_end_new_position).
|
||||
// Each group describes a change in text; groups are sorted by change_begin.
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditPatchFunctionPositions) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
|
||||
RUNTIME_ASSERT(SharedInfoWrapper::IsInstance(shared_array))
|
||||
|
||||
LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
// For array of SharedFunctionInfo's (each wrapped in JSValue)
|
||||
// checks that none of them have activations on stacks (of any thread).
|
||||
// Returns array of the same length with corresponding results of
|
||||
// LiveEdit::FunctionPatchabilityStatus type.
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditCheckAndDropActivations) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
|
||||
CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
|
||||
RUNTIME_ASSERT(shared_array->length()->IsSmi());
|
||||
RUNTIME_ASSERT(shared_array->HasFastElements())
|
||||
int array_length = Smi::cast(shared_array->length())->value();
|
||||
for (int i = 0; i < array_length; i++) {
|
||||
Handle<Object> element =
|
||||
Object::GetElement(isolate, shared_array, i).ToHandleChecked();
|
||||
RUNTIME_ASSERT(
|
||||
element->IsJSValue() &&
|
||||
Handle<JSValue>::cast(element)->value()->IsSharedFunctionInfo());
|
||||
}
|
||||
|
||||
return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
|
||||
}
|
||||
|
||||
|
||||
// Compares 2 strings line-by-line, then token-wise and returns diff in form
|
||||
// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
|
||||
// of diff chunks.
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditCompareStrings) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
|
||||
|
||||
return *LiveEdit::CompareStrings(s1, s2);
|
||||
}
|
||||
|
||||
|
||||
// Restarts a call frame and completely drops all frames above.
|
||||
// Returns true if successful. Otherwise returns undefined or an error message.
|
||||
RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK(isolate->debug()->live_edit_enabled());
|
||||
DCHECK(args.length() == 2);
|
||||
CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
|
||||
RUNTIME_ASSERT(isolate->debug()->CheckExecutionState(break_id));
|
||||
|
||||
CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
|
||||
Heap* heap = isolate->heap();
|
||||
|
||||
// Find the relevant frame with the requested index.
|
||||
StackFrame::Id id = isolate->debug()->break_frame_id();
|
||||
if (id == StackFrame::NO_ID) {
|
||||
// If there are no JavaScript stack frames return undefined.
|
||||
return heap->undefined_value();
|
||||
}
|
||||
|
||||
JavaScriptFrameIterator it(isolate, id);
|
||||
int inlined_jsframe_index = FindIndexedNonNativeFrame(&it, index);
|
||||
if (inlined_jsframe_index == -1) return heap->undefined_value();
|
||||
// We don't really care what the inlined frame index is, since we are
|
||||
// throwing away the entire frame anyways.
|
||||
const char* error_message = LiveEdit::RestartFrame(it.frame());
|
||||
if (error_message) {
|
||||
return *(isolate->factory()->InternalizeUtf8String(error_message));
|
||||
}
|
||||
return heap->true_value();
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal
|
@ -292,6 +292,61 @@ RUNTIME_FUNCTION(Runtime_AbortJS) {
|
||||
}
|
||||
|
||||
|
||||
// Returns V8 version as a string.
|
||||
RUNTIME_FUNCTION(Runtime_GetV8Version) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
|
||||
const char* version_string = v8::V8::GetVersion();
|
||||
|
||||
return *isolate->factory()->NewStringFromAsciiChecked(version_string);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
// ListNatives is ONLY used by the fuzz-natives.js in debug mode
|
||||
// Exclude the code in release mode.
|
||||
RUNTIME_FUNCTION(Runtime_ListNatives) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
#define COUNT_ENTRY(Name, argc, ressize) +1
|
||||
int entry_count =
|
||||
0 RUNTIME_FUNCTION_LIST(COUNT_ENTRY) INLINE_FUNCTION_LIST(COUNT_ENTRY)
|
||||
INLINE_OPTIMIZED_FUNCTION_LIST(COUNT_ENTRY);
|
||||
#undef COUNT_ENTRY
|
||||
Factory* factory = isolate->factory();
|
||||
Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
|
||||
int index = 0;
|
||||
bool inline_runtime_functions = false;
|
||||
#define ADD_ENTRY(Name, argc, ressize) \
|
||||
{ \
|
||||
HandleScope inner(isolate); \
|
||||
Handle<String> name; \
|
||||
/* Inline runtime functions have an underscore in front of the name. */ \
|
||||
if (inline_runtime_functions) { \
|
||||
name = factory->NewStringFromStaticChars("_" #Name); \
|
||||
} else { \
|
||||
name = factory->NewStringFromStaticChars(#Name); \
|
||||
} \
|
||||
Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
|
||||
pair_elements->set(0, *name); \
|
||||
pair_elements->set(1, Smi::FromInt(argc)); \
|
||||
Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
|
||||
elements->set(index++, *pair); \
|
||||
}
|
||||
inline_runtime_functions = false;
|
||||
RUNTIME_FUNCTION_LIST(ADD_ENTRY)
|
||||
INLINE_OPTIMIZED_FUNCTION_LIST(ADD_ENTRY)
|
||||
inline_runtime_functions = true;
|
||||
INLINE_FUNCTION_LIST(ADD_ENTRY)
|
||||
#undef ADD_ENTRY
|
||||
DCHECK_EQ(index, entry_count);
|
||||
Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
|
||||
return *result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_HaveSameMap) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 2);
|
||||
@ -319,5 +374,27 @@ ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
|
||||
ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)
|
||||
|
||||
#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
|
||||
|
||||
|
||||
#define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \
|
||||
RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) { \
|
||||
CONVERT_ARG_CHECKED(JSObject, obj, 0); \
|
||||
return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \
|
||||
}
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
|
||||
|
||||
#undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
|
||||
|
||||
|
||||
#define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \
|
||||
RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \
|
||||
CONVERT_ARG_CHECKED(JSObject, obj, 0); \
|
||||
return isolate->heap()->ToBoolean(obj->HasFixed##Type##Elements()); \
|
||||
}
|
||||
|
||||
TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
|
||||
|
||||
#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
|
||||
}
|
||||
} // namespace v8::internal
|
||||
|
@ -140,6 +140,10 @@ static inline ObjectPair MakePair(Object* x, Object* y) {
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
class JavaScriptFrameIterator;
|
||||
|
||||
int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index);
|
||||
}
|
||||
} // namespace v8::internal
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -737,8 +737,12 @@
|
||||
'../../src/runtime-profiler.h',
|
||||
'../../src/runtime/runtime-collections.cc',
|
||||
'../../src/runtime/runtime-compiler.cc',
|
||||
'../../src/runtime/runtime-date.cc',
|
||||
'../../src/runtime/runtime-debug.cc',
|
||||
'../../src/runtime/runtime-generator.cc',
|
||||
'../../src/runtime/runtime-i18n.cc',
|
||||
'../../src/runtime/runtime-json.cc',
|
||||
'../../src/runtime/runtime-liveedit.cc',
|
||||
'../../src/runtime/runtime-maths.cc',
|
||||
'../../src/runtime/runtime-numbers.cc',
|
||||
'../../src/runtime/runtime-regexp.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user