blob: ef7a4acc2580ed4944a7354df1effa9e93d288a2 [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
43#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000044#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000045#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "platform.h"
47#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000050#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000051#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000053#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
kasperl@chromium.org71affb52009-05-26 05:44:31 +000055namespace v8 {
56namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
58
ager@chromium.org3e875802009-06-29 08:26:34 +000059#define RUNTIME_ASSERT(value) \
60 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62// Cast the given object to a value of the specified type and store
63// it in a variable with the given name. If the object is not of the
64// expected type call IllegalOperation and return.
65#define CONVERT_CHECKED(Type, name, obj) \
66 RUNTIME_ASSERT(obj->Is##Type()); \
67 Type* name = Type::cast(obj);
68
69#define CONVERT_ARG_CHECKED(Type, name, index) \
70 RUNTIME_ASSERT(args[index]->Is##Type()); \
71 Handle<Type> name = args.at<Type>(index);
72
kasper.lundbd3ec4e2008-07-09 11:06:54 +000073// Cast the given object to a boolean and store it in a variable with
74// the given name. If the object is not a boolean call IllegalOperation
75// and return.
76#define CONVERT_BOOLEAN_CHECKED(name, obj) \
77 RUNTIME_ASSERT(obj->IsBoolean()); \
78 bool name = (obj)->IsTrue();
79
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000080// Cast the given object to a Smi and store its value in an int variable
81// with the given name. If the object is not a Smi call IllegalOperation
82// and return.
83#define CONVERT_SMI_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsSmi()); \
85 int name = Smi::cast(obj)->value();
86
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087// Cast the given object to a double and store it in a variable with
88// the given name. If the object is not a number (as opposed to
89// the number not-a-number) call IllegalOperation and return.
90#define CONVERT_DOUBLE_CHECKED(name, obj) \
91 RUNTIME_ASSERT(obj->IsNumber()); \
92 double name = (obj)->Number();
93
94// Call the specified converter on the object *comand store the result in
95// a variable of the specified type with the given name. If the
96// object is not a Number call IllegalOperation and return.
97#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
98 RUNTIME_ASSERT(obj->IsNumber()); \
99 type name = NumberTo##Type(obj);
100
101// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000102static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104
lrn@chromium.org303ada72010-10-27 09:33:13 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000106 StackLimitCheck check;
107 if (check.HasOverflowed()) return Top::StackOverflow();
108
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 Object* result;
110 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000113 JSObject* copy = JSObject::cast(result);
114
115 // Deep copy local properties.
116 if (copy->HasFastProperties()) {
117 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 for (int i = 0; i < properties->length(); i++) {
119 Object* value = properties->get(i);
120 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000122 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
123 if (!maybe_result->ToObject(&result)) return maybe_result;
124 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126 }
127 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000128 int nof = copy->map()->inobject_properties();
129 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 Object* value = copy->InObjectPropertyAt(i);
131 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000132 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000133 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
134 if (!maybe_result->ToObject(&result)) return maybe_result;
135 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000137 }
138 }
139 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 { MaybeObject* maybe_result =
141 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
142 if (!maybe_result->ToObject(&result)) return maybe_result;
143 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000144 FixedArray* names = FixedArray::cast(result);
145 copy->GetLocalPropertyNames(names, 0);
146 for (int i = 0; i < names->length(); i++) {
147 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 // Only deep copy fields from the object literal expression.
152 // In particular, don't try to copy the length attribute of
153 // an array.
154 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000155 Object* value =
156 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000158 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
160 if (!maybe_result->ToObject(&result)) return maybe_result;
161 }
162 { MaybeObject* maybe_result =
163 copy->SetProperty(key_string, result, NONE);
164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 }
167 }
168 }
169
170 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000171 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000172 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 switch (copy->GetElementsKind()) {
174 case JSObject::FAST_ELEMENTS: {
175 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000176 if (elements->map() == Heap::fixed_cow_array_map()) {
177 Counters::cow_arrays_created_runtime.Increment();
178#ifdef DEBUG
179 for (int i = 0; i < elements->length(); i++) {
180 ASSERT(!elements->get(i)->IsJSObject());
181 }
182#endif
183 } else {
184 for (int i = 0; i < elements->length(); i++) {
185 Object* value = elements->get(i);
186 if (value->IsJSObject()) {
187 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000188 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
189 if (!maybe_result->ToObject(&result)) return maybe_result;
190 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000191 elements->set(i, result);
192 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 }
194 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000195 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000197 case JSObject::DICTIONARY_ELEMENTS: {
198 NumberDictionary* element_dictionary = copy->element_dictionary();
199 int capacity = element_dictionary->Capacity();
200 for (int i = 0; i < capacity; i++) {
201 Object* k = element_dictionary->KeyAt(i);
202 if (element_dictionary->IsKey(k)) {
203 Object* value = element_dictionary->ValueAt(i);
204 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000206 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
207 if (!maybe_result->ToObject(&result)) return maybe_result;
208 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 element_dictionary->ValueAtPut(i, result);
210 }
211 }
212 }
213 break;
214 }
215 default:
216 UNREACHABLE();
217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
219 return copy;
220}
221
222
lrn@chromium.org303ada72010-10-27 09:33:13 +0000223static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
225 return DeepCopyBoilerplate(boilerplate);
226}
227
228
lrn@chromium.org303ada72010-10-27 09:33:13 +0000229static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000231 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232}
233
234
ager@chromium.org236ad962008-09-25 09:45:57 +0000235static Handle<Map> ComputeObjectLiteralMap(
236 Handle<Context> context,
237 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000238 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000239 int properties_length = constant_properties->length();
240 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000241 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000243 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 for (int p = 0; p != properties_length; p += 2) {
245 Object* key = constant_properties->get(p);
246 uint32_t element_index = 0;
247 if (key->IsSymbol()) {
248 number_of_symbol_keys++;
249 } else if (key->ToArrayIndex(&element_index)) {
250 // An index key does not require space in the property backing store.
251 number_of_properties--;
252 } else {
253 // Bail out as a non-symbol non-index key makes caching impossible.
254 // ASSERT to make sure that the if condition after the loop is false.
255 ASSERT(number_of_symbol_keys != number_of_properties);
256 break;
257 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 // If we only have symbols and array indices among keys then we can
260 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000262 if ((number_of_symbol_keys == number_of_properties) &&
263 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 // Create the fixed array with the key.
265 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 if (number_of_symbol_keys > 0) {
267 int index = 0;
268 for (int p = 0; p < properties_length; p += 2) {
269 Object* key = constant_properties->get(p);
270 if (key->IsSymbol()) {
271 keys->set(index++, key);
272 }
273 }
274 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000276 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 return Factory::ObjectLiteralMapFromCache(context, keys);
278 }
279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000281 return Factory::CopyMap(
282 Handle<Map>(context->object_function()->initial_map()),
283 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284}
285
286
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000287static Handle<Object> CreateLiteralBoilerplate(
288 Handle<FixedArray> literals,
289 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000290
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000291
292static Handle<Object> CreateObjectLiteralBoilerplate(
293 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000294 Handle<FixedArray> constant_properties,
295 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000296 // Get the global context from the literals array. This is the
297 // context in which the function was created and we use the object
298 // function from this context to create the object literal. We do
299 // not use the object function from the current global context
300 // because this might be the object function from another context
301 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 Handle<Context> context =
303 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
304
305 bool is_result_from_cache;
306 Handle<Map> map = ComputeObjectLiteralMap(context,
307 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000308 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309
ager@chromium.org236ad962008-09-25 09:45:57 +0000310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000311
312 // Normalize the elements of the boilerplate to save space if needed.
313 if (!should_have_fast_elements) NormalizeElements(boilerplate);
314
ager@chromium.org32912102009-01-16 10:38:43 +0000315 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000318 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 for (int index = 0; index < length; index +=2) {
321 Handle<Object> key(constant_properties->get(index+0));
322 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323 if (value->IsFixedArray()) {
324 // The value contains the constant_properties of a
325 // simple object literal.
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
327 value = CreateLiteralBoilerplate(literals, array);
328 if (value.is_null()) return value;
329 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000330 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000332 if (key->IsSymbol()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000333 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
334 // Array index as string (uint32).
335 result = SetOwnElement(boilerplate, element_index, value);
336 } else {
337 Handle<String> name(String::cast(*key));
338 ASSERT(!name->AsArrayIndex(&element_index));
339 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
340 value, NONE);
341 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000342 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 // Array index (uint32).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000344 result = SetOwnElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 } else {
346 // Non-uint32 number.
347 ASSERT(key->IsNumber());
348 double num = key->Number();
349 char arr[100];
350 Vector<char> buffer(arr, ARRAY_SIZE(arr));
351 const char* str = DoubleToCString(num, buffer);
352 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000353 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
354 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000356 // If setting the property on the boilerplate throws an
357 // exception, the exception is converted to an empty handle in
358 // the handle based operations. In that case, we need to
359 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000360 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 }
362 }
363
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000364 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000365}
366
367
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000368static Handle<Object> CreateArrayLiteralBoilerplate(
369 Handle<FixedArray> literals,
370 Handle<FixedArray> elements) {
371 // Create the JSArray.
372 Handle<JSFunction> constructor(
373 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
374 Handle<Object> object = Factory::NewJSObject(constructor);
375
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000376 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
377 Handle<FixedArray> copied_elements =
378 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000379
380 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000381 if (is_cow) {
382#ifdef DEBUG
383 // Copy-on-write arrays must be shallow (and simple).
384 for (int i = 0; i < content->length(); i++) {
385 ASSERT(!content->get(i)->IsFixedArray());
386 }
387#endif
388 } else {
389 for (int i = 0; i < content->length(); i++) {
390 if (content->get(i)->IsFixedArray()) {
391 // The value contains the constant_properties of a
392 // simple object literal.
393 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
394 Handle<Object> result =
395 CreateLiteralBoilerplate(literals, fa);
396 if (result.is_null()) return result;
397 content->set(i, *result);
398 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000399 }
400 }
401
402 // Set the elements.
403 Handle<JSArray>::cast(object)->SetContent(*content);
404 return object;
405}
406
407
408static Handle<Object> CreateLiteralBoilerplate(
409 Handle<FixedArray> literals,
410 Handle<FixedArray> array) {
411 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
412 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000413 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
414 return CreateObjectLiteralBoilerplate(literals, elements, true);
415 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
416 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417 case CompileTimeValue::ARRAY_LITERAL:
418 return CreateArrayLiteralBoilerplate(literals, elements);
419 default:
420 UNREACHABLE();
421 return Handle<Object>::null();
422 }
423}
424
425
lrn@chromium.org303ada72010-10-27 09:33:13 +0000426static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427 // Takes a FixedArray of elements containing the literal elements of
428 // the array literal and produces JSArray with those elements.
429 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000430 // which contains the context from which to get the Array function
431 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 HandleScope scope;
433 ASSERT(args.length() == 3);
434 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
435 CONVERT_SMI_CHECKED(literals_index, args[1]);
436 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
439 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 // Update the functions literal and return the boilerplate.
442 literals->set(literals_index, *object);
443 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444}
445
446
lrn@chromium.org303ada72010-10-27 09:33:13 +0000447static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000448 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000449 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000450 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
451 CONVERT_SMI_CHECKED(literals_index, args[1]);
452 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 CONVERT_SMI_CHECKED(fast_elements, args[3]);
454 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000455
456 // Check if boilerplate exists. If not, create it first.
457 Handle<Object> boilerplate(literals->get(literals_index));
458 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 boilerplate = CreateObjectLiteralBoilerplate(literals,
460 constant_properties,
461 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 if (boilerplate.is_null()) return Failure::Exception();
463 // Update the functions literal and return the boilerplate.
464 literals->set(literals_index, *boilerplate);
465 }
466 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
467}
468
469
lrn@chromium.org303ada72010-10-27 09:33:13 +0000470static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000471 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000472 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000473 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
474 CONVERT_SMI_CHECKED(literals_index, args[1]);
475 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000476 CONVERT_SMI_CHECKED(fast_elements, args[3]);
477 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000478
479 // Check if boilerplate exists. If not, create it first.
480 Handle<Object> boilerplate(literals->get(literals_index));
481 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000482 boilerplate = CreateObjectLiteralBoilerplate(literals,
483 constant_properties,
484 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000485 if (boilerplate.is_null()) return Failure::Exception();
486 // Update the functions literal and return the boilerplate.
487 literals->set(literals_index, *boilerplate);
488 }
489 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
490}
491
492
lrn@chromium.org303ada72010-10-27 09:33:13 +0000493static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494 HandleScope scope;
495 ASSERT(args.length() == 3);
496 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
497 CONVERT_SMI_CHECKED(literals_index, args[1]);
498 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
499
500 // Check if boilerplate exists. If not, create it first.
501 Handle<Object> boilerplate(literals->get(literals_index));
502 if (*boilerplate == Heap::undefined_value()) {
503 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
504 if (boilerplate.is_null()) return Failure::Exception();
505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *boilerplate);
507 }
508 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
509}
510
511
lrn@chromium.org303ada72010-10-27 09:33:13 +0000512static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000513 HandleScope scope;
514 ASSERT(args.length() == 3);
515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
516 CONVERT_SMI_CHECKED(literals_index, args[1]);
517 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
518
519 // Check if boilerplate exists. If not, create it first.
520 Handle<Object> boilerplate(literals->get(literals_index));
521 if (*boilerplate == Heap::undefined_value()) {
522 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
523 if (boilerplate.is_null()) return Failure::Exception();
524 // Update the functions literal and return the boilerplate.
525 literals->set(literals_index, *boilerplate);
526 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000527 if (JSObject::cast(*boilerplate)->elements()->map() ==
528 Heap::fixed_cow_array_map()) {
529 Counters::cow_arrays_created_runtime.Increment();
530 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
532}
533
534
lrn@chromium.org303ada72010-10-27 09:33:13 +0000535static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000536 ASSERT(args.length() == 2);
537 CONVERT_CHECKED(String, key, args[0]);
538 Object* value = args[1];
539 // Create a catch context extension object.
540 JSFunction* constructor =
541 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000542 Object* object;
543 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
544 if (!maybe_object->ToObject(&object)) return maybe_object;
545 }
ager@chromium.org32912102009-01-16 10:38:43 +0000546 // Assign the exception value to the catch variable and make sure
547 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000548 { MaybeObject* maybe_value =
549 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
550 if (!maybe_value->ToObject(&value)) return maybe_value;
551 }
ager@chromium.org32912102009-01-16 10:38:43 +0000552 return object;
553}
554
555
lrn@chromium.org303ada72010-10-27 09:33:13 +0000556static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 NoHandleAllocation ha;
558 ASSERT(args.length() == 1);
559 Object* obj = args[0];
560 if (!obj->IsJSObject()) return Heap::null_value();
561 return JSObject::cast(obj)->class_name();
562}
563
ager@chromium.org7c537e22008-10-16 08:43:32 +0000564
lrn@chromium.org303ada72010-10-27 09:33:13 +0000565static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 NoHandleAllocation ha;
567 ASSERT(args.length() == 2);
568 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
569 Object* O = args[0];
570 Object* V = args[1];
571 while (true) {
572 Object* prototype = V->GetPrototype();
573 if (prototype->IsNull()) return Heap::false_value();
574 if (O == prototype) return Heap::true_value();
575 V = prototype;
576 }
577}
578
579
ager@chromium.org9085a012009-05-11 19:22:57 +0000580// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000581static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000582 NoHandleAllocation ha;
583 ASSERT(args.length() == 2);
584 CONVERT_CHECKED(JSObject, jsobject, args[0]);
585 CONVERT_CHECKED(JSObject, proto, args[1]);
586
587 // Sanity checks. The old prototype (that we are replacing) could
588 // theoretically be null, but if it is not null then check that we
589 // didn't already install a hidden prototype here.
590 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
591 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
592 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
593
594 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000595 Object* map_or_failure;
596 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
597 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
598 return maybe_map_or_failure;
599 }
600 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000601 Map* new_proto_map = Map::cast(map_or_failure);
602
lrn@chromium.org303ada72010-10-27 09:33:13 +0000603 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
604 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
605 return maybe_map_or_failure;
606 }
607 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000608 Map* new_map = Map::cast(map_or_failure);
609
610 // Set proto's prototype to be the old prototype of the object.
611 new_proto_map->set_prototype(jsobject->GetPrototype());
612 proto->set_map(new_proto_map);
613 new_proto_map->set_is_hidden_prototype();
614
615 // Set the object's prototype to proto.
616 new_map->set_prototype(proto);
617 jsobject->set_map(new_map);
618
619 return Heap::undefined_value();
620}
621
622
lrn@chromium.org303ada72010-10-27 09:33:13 +0000623static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000625 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 JavaScriptFrameIterator it;
627 return Heap::ToBoolean(it.frame()->IsConstructor());
628}
629
630
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000631// Recursively traverses hidden prototypes if property is not found
632static void GetOwnPropertyImplementation(JSObject* obj,
633 String* name,
634 LookupResult* result) {
635 obj->LocalLookupRealNamedProperty(name, result);
636
637 if (!result->IsProperty()) {
638 Object* proto = obj->GetPrototype();
639 if (proto->IsJSObject() &&
640 JSObject::cast(proto)->map()->is_hidden_prototype())
641 GetOwnPropertyImplementation(JSObject::cast(proto),
642 name, result);
643 }
644}
645
646
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000647static bool CheckAccessException(LookupResult* result,
648 v8::AccessType access_type) {
649 if (result->type() == CALLBACKS) {
650 Object* callback = result->GetCallbackObject();
651 if (callback->IsAccessorInfo()) {
652 AccessorInfo* info = AccessorInfo::cast(callback);
653 bool can_access =
654 (access_type == v8::ACCESS_HAS &&
655 (info->all_can_read() || info->all_can_write())) ||
656 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
657 (access_type == v8::ACCESS_SET && info->all_can_write());
658 return can_access;
659 }
660 }
661
662 return false;
663}
664
665
666static bool CheckAccess(JSObject* obj,
667 String* name,
668 LookupResult* result,
669 v8::AccessType access_type) {
670 ASSERT(result->IsProperty());
671
672 JSObject* holder = result->holder();
673 JSObject* current = obj;
674 while (true) {
675 if (current->IsAccessCheckNeeded() &&
676 !Top::MayNamedAccess(current, name, access_type)) {
677 // Access check callback denied the access, but some properties
678 // can have a special permissions which override callbacks descision
679 // (currently see v8::AccessControl).
680 break;
681 }
682
683 if (current == holder) {
684 return true;
685 }
686
687 current = JSObject::cast(current->GetPrototype());
688 }
689
690 // API callbacks can have per callback access exceptions.
691 switch (result->type()) {
692 case CALLBACKS: {
693 if (CheckAccessException(result, access_type)) {
694 return true;
695 }
696 break;
697 }
698 case INTERCEPTOR: {
699 // If the object has an interceptor, try real named properties.
700 // Overwrite the result to fetch the correct property later.
701 holder->LookupRealNamedProperty(name, result);
702 if (result->IsProperty()) {
703 if (CheckAccessException(result, access_type)) {
704 return true;
705 }
706 }
707 break;
708 }
709 default:
710 break;
711 }
712
713 Top::ReportFailedAccessCheck(current, access_type);
714 return false;
715}
716
717
718// TODO(1095): we should traverse hidden prototype hierachy as well.
719static bool CheckElementAccess(JSObject* obj,
720 uint32_t index,
721 v8::AccessType access_type) {
722 if (obj->IsAccessCheckNeeded() &&
723 !Top::MayIndexedAccess(obj, index, access_type)) {
724 return false;
725 }
726
727 return true;
728}
729
730
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000731// Enumerator used as indices into the array returned from GetOwnProperty
732enum PropertyDescriptorIndices {
733 IS_ACCESSOR_INDEX,
734 VALUE_INDEX,
735 GETTER_INDEX,
736 SETTER_INDEX,
737 WRITABLE_INDEX,
738 ENUMERABLE_INDEX,
739 CONFIGURABLE_INDEX,
740 DESCRIPTOR_SIZE
741};
742
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000743// Returns an array with the property description:
744// if args[1] is not a property on args[0]
745// returns undefined
746// if args[1] is a data property on args[0]
747// [false, value, Writeable, Enumerable, Configurable]
748// if args[1] is an accessor on args[0]
749// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000750static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000751 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000752 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000753 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000754 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
755 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000756 CONVERT_ARG_CHECKED(JSObject, obj, 0);
757 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000759 // This could be an element.
760 uint32_t index;
761 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000762 switch (obj->HasLocalElement(index)) {
763 case JSObject::UNDEFINED_ELEMENT:
764 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000765
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000766 case JSObject::STRING_CHARACTER_ELEMENT: {
767 // Special handling of string objects according to ECMAScript 5
768 // 15.5.5.2. Note that this might be a string object with elements
769 // other than the actual string value. This is covered by the
770 // subsequent cases.
771 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
772 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000774
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000775 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
776 elms->set(VALUE_INDEX, *substr);
777 elms->set(WRITABLE_INDEX, Heap::false_value());
778 elms->set(ENUMERABLE_INDEX, Heap::false_value());
779 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
780 return *desc;
781 }
782
783 case JSObject::INTERCEPTED_ELEMENT:
784 case JSObject::FAST_ELEMENT: {
785 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000786 elms->set(VALUE_INDEX, *GetElement(obj, index));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000787 elms->set(WRITABLE_INDEX, Heap::true_value());
788 elms->set(ENUMERABLE_INDEX, Heap::true_value());
789 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
790 return *desc;
791 }
792
793 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000794 Handle<JSObject> holder = obj;
795 if (obj->IsJSGlobalProxy()) {
796 Object* proto = obj->GetPrototype();
797 if (proto->IsNull()) return Heap::undefined_value();
798 ASSERT(proto->IsJSGlobalObject());
799 holder = Handle<JSObject>(JSObject::cast(proto));
800 }
801 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000802 int entry = dictionary->FindEntry(index);
803 ASSERT(entry != NumberDictionary::kNotFound);
804 PropertyDetails details = dictionary->DetailsAt(entry);
805 switch (details.type()) {
806 case CALLBACKS: {
807 // This is an accessor property with getter and/or setter.
808 FixedArray* callbacks =
809 FixedArray::cast(dictionary->ValueAt(entry));
810 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000811 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
812 elms->set(GETTER_INDEX, callbacks->get(0));
813 }
814 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
815 elms->set(SETTER_INDEX, callbacks->get(1));
816 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000817 break;
818 }
819 case NORMAL:
820 // This is a data property.
821 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000822 elms->set(VALUE_INDEX, *GetElement(obj, index));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000823 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
824 break;
825 default:
826 UNREACHABLE();
827 break;
828 }
829 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
830 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
831 return *desc;
832 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000833 }
834 }
835
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000836 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000837 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000838
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000839 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000840 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000842
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000843 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
844 return Heap::false_value();
845 }
846
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000847 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
848 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000849
850 bool is_js_accessor = (result.type() == CALLBACKS) &&
851 (result.GetCallbackObject()->IsFixedArray());
852
853 if (is_js_accessor) {
854 // __defineGetter__/__defineSetter__ callback.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000855 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856
857 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
858 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
859 elms->set(GETTER_INDEX, structure->get(0));
860 }
861 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
862 elms->set(SETTER_INDEX, structure->get(1));
863 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000864 } else {
865 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
866 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
867
868 PropertyAttributes attrs;
869 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000870 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000871 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
872 if (!maybe_value->ToObject(&value)) return maybe_value;
873 }
874 elms->set(VALUE_INDEX, value);
875 }
876
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000877 return *desc;
878}
879
880
lrn@chromium.org303ada72010-10-27 09:33:13 +0000881static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000882 ASSERT(args.length() == 1);
883 CONVERT_CHECKED(JSObject, obj, args[0]);
884 return obj->PreventExtensions();
885}
886
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000887
lrn@chromium.org303ada72010-10-27 09:33:13 +0000888static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000889 ASSERT(args.length() == 1);
890 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000891 if (obj->IsJSGlobalProxy()) {
892 Object* proto = obj->GetPrototype();
893 if (proto->IsNull()) return Heap::false_value();
894 ASSERT(proto->IsJSGlobalObject());
895 obj = JSObject::cast(proto);
896 }
897 return obj->map()->is_extensible() ? Heap::true_value()
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000898 : Heap::false_value();
899}
900
901
lrn@chromium.org303ada72010-10-27 09:33:13 +0000902static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000903 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000905 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
906 CONVERT_ARG_CHECKED(String, pattern, 1);
907 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000908 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
909 if (result.is_null()) return Failure::Exception();
910 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911}
912
913
lrn@chromium.org303ada72010-10-27 09:33:13 +0000914static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915 HandleScope scope;
916 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000917 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000918 return *Factory::CreateApiFunction(data);
919}
920
921
lrn@chromium.org303ada72010-10-27 09:33:13 +0000922static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923 ASSERT(args.length() == 1);
924 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000925 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 return Heap::ToBoolean(result);
927}
928
929
lrn@chromium.org303ada72010-10-27 09:33:13 +0000930static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 ASSERT(args.length() == 2);
932 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000934 int index = field->value();
935 int offset = index * kPointerSize + HeapObject::kHeaderSize;
936 InstanceType type = templ->map()->instance_type();
937 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
938 type == OBJECT_TEMPLATE_INFO_TYPE);
939 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000940 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000941 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
942 } else {
943 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
944 }
945 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000946}
947
948
lrn@chromium.org303ada72010-10-27 09:33:13 +0000949static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000950 ASSERT(args.length() == 1);
951 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000952 Map* old_map = object->map();
953 bool needs_access_checks = old_map->is_access_check_needed();
954 if (needs_access_checks) {
955 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000956 Object* new_map;
957 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
958 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
959 }
ager@chromium.org32912102009-01-16 10:38:43 +0000960
961 Map::cast(new_map)->set_is_access_check_needed(false);
962 object->set_map(Map::cast(new_map));
963 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000964 return needs_access_checks ? Heap::true_value() : Heap::false_value();
965}
966
967
lrn@chromium.org303ada72010-10-27 09:33:13 +0000968static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000969 ASSERT(args.length() == 1);
970 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000971 Map* old_map = object->map();
972 if (!old_map->is_access_check_needed()) {
973 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000974 Object* new_map;
975 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
976 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
977 }
ager@chromium.org32912102009-01-16 10:38:43 +0000978
979 Map::cast(new_map)->set_is_access_check_needed(true);
980 object->set_map(Map::cast(new_map));
981 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000982 return Heap::undefined_value();
983}
984
985
lrn@chromium.org303ada72010-10-27 09:33:13 +0000986static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987 HandleScope scope;
988 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
989 Handle<Object> args[2] = { type_handle, name };
990 Handle<Object> error =
991 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
992 return Top::Throw(*error);
993}
994
995
lrn@chromium.org303ada72010-10-27 09:33:13 +0000996static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 HandleScope scope;
998 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
999
ager@chromium.org3811b432009-10-28 14:53:37 +00001000 Handle<Context> context = args.at<Context>(0);
1001 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 bool is_eval = Smi::cast(args[2])->value() == 1;
1003
1004 // Compute the property attributes. According to ECMA-262, section
1005 // 13, page 71, the property must be read-only and
1006 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1007 // property as read-only, so we don't either.
1008 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1009
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 // Traverse the name/value pairs and set the properties.
1011 int length = pairs->length();
1012 for (int i = 0; i < length; i += 2) {
1013 HandleScope scope;
1014 Handle<String> name(String::cast(pairs->get(i)));
1015 Handle<Object> value(pairs->get(i + 1));
1016
1017 // We have to declare a global const property. To capture we only
1018 // assign to it when evaluating the assignment for "const x =
1019 // <expr>" the initial value is the hole.
1020 bool is_const_property = value->IsTheHole();
1021
1022 if (value->IsUndefined() || is_const_property) {
1023 // Lookup the property in the global object, and don't set the
1024 // value of the variable if the property is already there.
1025 LookupResult lookup;
1026 global->Lookup(*name, &lookup);
1027 if (lookup.IsProperty()) {
1028 // Determine if the property is local by comparing the holder
1029 // against the global object. The information will be used to
1030 // avoid throwing re-declaration errors when declaring
1031 // variables or constants that exist in the prototype chain.
1032 bool is_local = (*global == lookup.holder());
1033 // Get the property attributes and determine if the property is
1034 // read-only.
1035 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1036 bool is_read_only = (attributes & READ_ONLY) != 0;
1037 if (lookup.type() == INTERCEPTOR) {
1038 // If the interceptor says the property is there, we
1039 // just return undefined without overwriting the property.
1040 // Otherwise, we continue to setting the property.
1041 if (attributes != ABSENT) {
1042 // Check if the existing property conflicts with regards to const.
1043 if (is_local && (is_read_only || is_const_property)) {
1044 const char* type = (is_read_only) ? "const" : "var";
1045 return ThrowRedeclarationError(type, name);
1046 };
1047 // The property already exists without conflicting: Go to
1048 // the next declaration.
1049 continue;
1050 }
1051 // Fall-through and introduce the absent property by using
1052 // SetProperty.
1053 } else {
1054 if (is_local && (is_read_only || is_const_property)) {
1055 const char* type = (is_read_only) ? "const" : "var";
1056 return ThrowRedeclarationError(type, name);
1057 }
1058 // The property already exists without conflicting: Go to
1059 // the next declaration.
1060 continue;
1061 }
1062 }
1063 } else {
1064 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001065 Handle<SharedFunctionInfo> shared =
1066 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001067 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001068 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 value = function;
1070 }
1071
1072 LookupResult lookup;
1073 global->LocalLookup(*name, &lookup);
1074
1075 PropertyAttributes attributes = is_const_property
1076 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1077 : base;
1078
1079 if (lookup.IsProperty()) {
1080 // There's a local property that we need to overwrite because
1081 // we're either declaring a function or there's an interceptor
1082 // that claims the property is absent.
1083
1084 // Check for conflicting re-declarations. We cannot have
1085 // conflicting types in case of intercepted properties because
1086 // they are absent.
1087 if (lookup.type() != INTERCEPTOR &&
1088 (lookup.IsReadOnly() || is_const_property)) {
1089 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
1090 return ThrowRedeclarationError(type, name);
1091 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001092 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093 } else {
1094 // If a property with this name does not already exist on the
1095 // global object add the property locally. We take special
1096 // precautions to always add it as a local property even in case
1097 // of callbacks in the prototype chain (this rules out using
1098 // SetProperty). Also, we must use the handle-based version to
1099 // avoid GC issues.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001100 RETURN_IF_EMPTY_HANDLE(
1101 SetLocalPropertyIgnoreAttributes(global, name, value, attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 }
1103 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001104
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001105 ASSERT(!Top::has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 return Heap::undefined_value();
1107}
1108
1109
lrn@chromium.org303ada72010-10-27 09:33:13 +00001110static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001112 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113
ager@chromium.org7c537e22008-10-16 08:43:32 +00001114 CONVERT_ARG_CHECKED(Context, context, 0);
1115 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001117 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001118 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001119 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120
1121 // Declarations are always done in the function context.
1122 context = Handle<Context>(context->fcontext());
1123
1124 int index;
1125 PropertyAttributes attributes;
1126 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001127 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001128 context->Lookup(name, flags, &index, &attributes);
1129
1130 if (attributes != ABSENT) {
1131 // The name was declared before; check for conflicting
1132 // re-declarations: This is similar to the code in parser.cc in
1133 // the AstBuildingParser::Declare function.
1134 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1135 // Functions are not read-only.
1136 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1137 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1138 return ThrowRedeclarationError(type, name);
1139 }
1140
1141 // Initialize it if necessary.
1142 if (*initial_value != NULL) {
1143 if (index >= 0) {
1144 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001145 // the function context or the arguments object.
1146 if (holder->IsContext()) {
1147 ASSERT(holder.is_identical_to(context));
1148 if (((attributes & READ_ONLY) == 0) ||
1149 context->get(index)->IsTheHole()) {
1150 context->set(index, *initial_value);
1151 }
1152 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001153 // The holder is an arguments object.
1154 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001155 Handle<Object> result = SetElement(arguments, index, initial_value);
1156 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157 }
1158 } else {
1159 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001160 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001161 RETURN_IF_EMPTY_HANDLE(
1162 SetProperty(context_ext, name, initial_value, mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 }
1164 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001167 // The property is not in the function context. It needs to be
1168 // "declared" in the function context's extension context, or in the
1169 // global context.
1170 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001171 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001172 // The function context's extension context exists - use it.
1173 context_ext = Handle<JSObject>(context->extension());
1174 } else {
1175 // The function context's extension context does not exists - allocate
1176 // it.
1177 context_ext = Factory::NewJSObject(Top::context_extension_function());
1178 // And store it in the extension slot.
1179 context->set_extension(*context_ext);
1180 }
1181 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182
ager@chromium.org7c537e22008-10-16 08:43:32 +00001183 // Declare the property by setting it to the initial value if provided,
1184 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1185 // constant declarations).
1186 ASSERT(!context_ext->HasLocalProperty(*name));
1187 Handle<Object> value(Heap::undefined_value());
1188 if (*initial_value != NULL) value = initial_value;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001189 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, mode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001190 }
1191
1192 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
lrn@chromium.org303ada72010-10-27 09:33:13 +00001196static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 NoHandleAllocation nha;
1198
1199 // Determine if we need to assign to the variable if it already
1200 // exists (based on the number of arguments).
1201 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1202 bool assign = args.length() == 2;
1203
1204 CONVERT_ARG_CHECKED(String, name, 0);
1205 GlobalObject* global = Top::context()->global();
1206
1207 // According to ECMA-262, section 12.2, page 62, the property must
1208 // not be deletable.
1209 PropertyAttributes attributes = DONT_DELETE;
1210
1211 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001212 // there, there is a property with this name in the prototype chain.
1213 // We follow Safari and Firefox behavior and only set the property
1214 // locally if there is an explicit initialization value that we have
1215 // to assign to the property. When adding the property we take
1216 // special precautions to always add it as a local property even in
1217 // case of callbacks in the prototype chain (this rules out using
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001218 // SetProperty). We have SetLocalPropertyIgnoreAttributes for
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001219 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001220 // Note that objects can have hidden prototypes, so we need to traverse
1221 // the whole chain of hidden prototypes to do a 'local' lookup.
1222 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001224 while (true) {
1225 real_holder->LocalLookup(*name, &lookup);
1226 if (lookup.IsProperty()) {
1227 // Determine if this is a redeclaration of something read-only.
1228 if (lookup.IsReadOnly()) {
1229 // If we found readonly property on one of hidden prototypes,
1230 // just shadow it.
1231 if (real_holder != Top::context()->global()) break;
1232 return ThrowRedeclarationError("const", name);
1233 }
1234
1235 // Determine if this is a redeclaration of an intercepted read-only
1236 // property and figure out if the property exists at all.
1237 bool found = true;
1238 PropertyType type = lookup.type();
1239 if (type == INTERCEPTOR) {
1240 HandleScope handle_scope;
1241 Handle<JSObject> holder(real_holder);
1242 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1243 real_holder = *holder;
1244 if (intercepted == ABSENT) {
1245 // The interceptor claims the property isn't there. We need to
1246 // make sure to introduce it.
1247 found = false;
1248 } else if ((intercepted & READ_ONLY) != 0) {
1249 // The property is present, but read-only. Since we're trying to
1250 // overwrite it with a variable declaration we must throw a
1251 // re-declaration error. However if we found readonly property
1252 // on one of hidden prototypes, just shadow it.
1253 if (real_holder != Top::context()->global()) break;
1254 return ThrowRedeclarationError("const", name);
1255 }
1256 }
1257
1258 if (found && !assign) {
1259 // The global property is there and we're not assigning any value
1260 // to it. Just return.
1261 return Heap::undefined_value();
1262 }
1263
1264 // Assign the value (or undefined) to the property.
1265 Object* value = (assign) ? args[1] : Heap::undefined_value();
1266 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001267 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001268
1269 Object* proto = real_holder->GetPrototype();
1270 if (!proto->IsJSObject())
1271 break;
1272
1273 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1274 break;
1275
1276 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 }
1278
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001279 global = Top::context()->global();
1280 if (assign) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001281 return global->SetLocalPropertyIgnoreAttributes(*name,
1282 args[1],
1283 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001285 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286}
1287
1288
lrn@chromium.org303ada72010-10-27 09:33:13 +00001289static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290 // All constants are declared with an initial value. The name
1291 // of the constant is the first argument and the initial value
1292 // is the second.
1293 RUNTIME_ASSERT(args.length() == 2);
1294 CONVERT_ARG_CHECKED(String, name, 0);
1295 Handle<Object> value = args.at<Object>(1);
1296
1297 // Get the current global object from top.
1298 GlobalObject* global = Top::context()->global();
1299
1300 // According to ECMA-262, section 12.2, page 62, the property must
1301 // not be deletable. Since it's a const, it must be READ_ONLY too.
1302 PropertyAttributes attributes =
1303 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1304
1305 // Lookup the property locally in the global object. If it isn't
1306 // there, we add the property and take special precautions to always
1307 // add it as a local property even in case of callbacks in the
1308 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001309 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 LookupResult lookup;
1311 global->LocalLookup(*name, &lookup);
1312 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001313 return global->SetLocalPropertyIgnoreAttributes(*name,
1314 *value,
1315 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 }
1317
1318 // Determine if this is a redeclaration of something not
1319 // read-only. In case the result is hidden behind an interceptor we
1320 // need to ask it for the property attributes.
1321 if (!lookup.IsReadOnly()) {
1322 if (lookup.type() != INTERCEPTOR) {
1323 return ThrowRedeclarationError("var", name);
1324 }
1325
1326 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1327
1328 // Throw re-declaration error if the intercepted property is present
1329 // but not read-only.
1330 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1331 return ThrowRedeclarationError("var", name);
1332 }
1333
1334 // Restore global object from context (in case of GC) and continue
1335 // with setting the value because the property is either absent or
1336 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001337 HandleScope handle_scope;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001338 Handle<GlobalObject> global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001340 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 // property through an interceptor and only do it if it's
1342 // uninitialized, e.g. the hole. Nirk...
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001343 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 return *value;
1345 }
1346
1347 // Set the value, but only we're assigning the initial value to a
1348 // constant. For now, we determine this by checking if the
1349 // current value is the hole.
1350 PropertyType type = lookup.type();
1351 if (type == FIELD) {
1352 FixedArray* properties = global->properties();
1353 int index = lookup.GetFieldIndex();
1354 if (properties->get(index)->IsTheHole()) {
1355 properties->set(index, *value);
1356 }
1357 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001358 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1359 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 }
1361 } else {
1362 // Ignore re-initialization of constants that have already been
1363 // assigned a function value.
1364 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1365 }
1366
1367 // Use the set value as the result of the operation.
1368 return *value;
1369}
1370
1371
lrn@chromium.org303ada72010-10-27 09:33:13 +00001372static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373 HandleScope scope;
1374 ASSERT(args.length() == 3);
1375
1376 Handle<Object> value(args[0]);
1377 ASSERT(!value->IsTheHole());
1378 CONVERT_ARG_CHECKED(Context, context, 1);
1379 Handle<String> name(String::cast(args[2]));
1380
1381 // Initializations are always done in the function context.
1382 context = Handle<Context>(context->fcontext());
1383
1384 int index;
1385 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001386 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001387 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388 context->Lookup(name, flags, &index, &attributes);
1389
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001390 // In most situations, the property introduced by the const
1391 // declaration should be present in the context extension object.
1392 // However, because declaration and initialization are separate, the
1393 // property might have been deleted (if it was introduced by eval)
1394 // before we reach the initialization point.
1395 //
1396 // Example:
1397 //
1398 // function f() { eval("delete x; const x;"); }
1399 //
1400 // In that case, the initialization behaves like a normal assignment
1401 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001403 // Property was found in a context.
1404 if (holder->IsContext()) {
1405 // The holder cannot be the function context. If it is, there
1406 // should have been a const redeclaration error when declaring
1407 // the const property.
1408 ASSERT(!holder.is_identical_to(context));
1409 if ((attributes & READ_ONLY) == 0) {
1410 Handle<Context>::cast(holder)->set(index, *value);
1411 }
1412 } else {
1413 // The holder is an arguments object.
1414 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001415 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1416 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 }
1418 return *value;
1419 }
1420
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001421 // The property could not be found, we introduce it in the global
1422 // context.
1423 if (attributes == ABSENT) {
1424 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001425 RETURN_IF_EMPTY_HANDLE(SetProperty(global, name, value, NONE));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001426 return *value;
1427 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001428
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001429 // The property was present in a context extension object.
1430 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001432 if (*context_ext == context->extension()) {
1433 // This is the property that was introduced by the const
1434 // declaration. Set it if it hasn't been set before. NOTE: We
1435 // cannot use GetProperty() to get the current value as it
1436 // 'unholes' the value.
1437 LookupResult lookup;
1438 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1439 ASSERT(lookup.IsProperty()); // the property was declared
1440 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1441
1442 PropertyType type = lookup.type();
1443 if (type == FIELD) {
1444 FixedArray* properties = context_ext->properties();
1445 int index = lookup.GetFieldIndex();
1446 if (properties->get(index)->IsTheHole()) {
1447 properties->set(index, *value);
1448 }
1449 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001450 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1451 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001452 }
1453 } else {
1454 // We should not reach here. Any real, named property should be
1455 // either a field or a dictionary slot.
1456 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001457 }
1458 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001459 // The property was found in a different context extension object.
1460 // Set it if it is not a read-only property.
1461 if ((attributes & READ_ONLY) == 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001462 RETURN_IF_EMPTY_HANDLE(
1463 SetProperty(context_ext, name, value, attributes));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001464 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467 return *value;
1468}
1469
1470
lrn@chromium.org303ada72010-10-27 09:33:13 +00001471static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001472 Arguments args) {
1473 HandleScope scope;
1474 ASSERT(args.length() == 2);
1475 CONVERT_ARG_CHECKED(JSObject, object, 0);
1476 CONVERT_SMI_CHECKED(properties, args[1]);
1477 if (object->HasFastProperties()) {
1478 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1479 }
1480 return *object;
1481}
1482
1483
lrn@chromium.org303ada72010-10-27 09:33:13 +00001484static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001486 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001487 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1488 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001489 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001490 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001491 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001492 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001493 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001494 RUNTIME_ASSERT(index >= 0);
1495 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001496 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001497 Handle<Object> result = RegExpImpl::Exec(regexp,
1498 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001499 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001500 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001501 if (result.is_null()) return Failure::Exception();
1502 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503}
1504
1505
lrn@chromium.org303ada72010-10-27 09:33:13 +00001506static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001507 ASSERT(args.length() == 3);
1508 CONVERT_SMI_CHECKED(elements_count, args[0]);
1509 if (elements_count > JSArray::kMaxFastElementsLength) {
1510 return Top::ThrowIllegalOperation();
1511 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001512 Object* new_object;
1513 { MaybeObject* maybe_new_object =
1514 Heap::AllocateFixedArrayWithHoles(elements_count);
1515 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1516 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001517 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001518 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1519 NEW_SPACE,
1520 OLD_POINTER_SPACE);
1521 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1522 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001523 {
1524 AssertNoAllocation no_gc;
1525 HandleScope scope;
1526 reinterpret_cast<HeapObject*>(new_object)->
1527 set_map(Top::global_context()->regexp_result_map());
1528 }
1529 JSArray* array = JSArray::cast(new_object);
1530 array->set_properties(Heap::empty_fixed_array());
1531 array->set_elements(elements);
1532 array->set_length(Smi::FromInt(elements_count));
1533 // Write in-object properties after the length of the array.
1534 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1535 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1536 return array;
1537}
1538
1539
lrn@chromium.org303ada72010-10-27 09:33:13 +00001540static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001541 AssertNoAllocation no_alloc;
1542 ASSERT(args.length() == 5);
1543 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1544 CONVERT_CHECKED(String, source, args[1]);
1545
1546 Object* global = args[2];
1547 if (!global->IsTrue()) global = Heap::false_value();
1548
1549 Object* ignoreCase = args[3];
1550 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1551
1552 Object* multiline = args[4];
1553 if (!multiline->IsTrue()) multiline = Heap::false_value();
1554
1555 Map* map = regexp->map();
1556 Object* constructor = map->constructor();
1557 if (constructor->IsJSFunction() &&
1558 JSFunction::cast(constructor)->initial_map() == map) {
1559 // If we still have the original map, set in-object properties directly.
1560 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1561 // TODO(lrn): Consider skipping write barrier on booleans as well.
1562 // Both true and false should be in oldspace at all times.
1563 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1564 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1565 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1566 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1567 Smi::FromInt(0),
1568 SKIP_WRITE_BARRIER);
1569 return regexp;
1570 }
1571
lrn@chromium.org303ada72010-10-27 09:33:13 +00001572 // Map has changed, so use generic, but slower, method. Since these
1573 // properties were all added as DONT_DELETE they must be present and
1574 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001575 PropertyAttributes final =
1576 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1577 PropertyAttributes writable =
1578 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001579 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001580 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1581 source,
1582 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001583 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001584 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1585 global,
1586 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001587 ASSERT(!result->IsFailure());
1588 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001589 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1590 ignoreCase,
1591 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001592 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001593 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1594 multiline,
1595 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001596 ASSERT(!result->IsFailure());
1597 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001598 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1599 Smi::FromInt(0),
1600 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001601 ASSERT(!result->IsFailure());
1602 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001603 return regexp;
1604}
1605
1606
lrn@chromium.org303ada72010-10-27 09:33:13 +00001607static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001608 HandleScope scope;
1609 ASSERT(args.length() == 1);
1610 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1611 // This is necessary to enable fast checks for absence of elements
1612 // on Array.prototype and below.
1613 prototype->set_elements(Heap::empty_fixed_array());
1614 return Smi::FromInt(0);
1615}
1616
1617
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001618static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1619 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001620 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001621 Handle<String> key = Factory::LookupAsciiSymbol(name);
1622 Handle<Code> code(Builtins::builtin(builtin_name));
1623 Handle<JSFunction> optimized = Factory::NewFunction(key,
1624 JS_OBJECT_TYPE,
1625 JSObject::kHeaderSize,
1626 code,
1627 false);
1628 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001629 SetProperty(holder, key, optimized, NONE);
1630 return optimized;
1631}
1632
1633
lrn@chromium.org303ada72010-10-27 09:33:13 +00001634static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001635 HandleScope scope;
1636 ASSERT(args.length() == 1);
1637 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1638
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001639 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1640 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001641 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1642 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1643 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1644 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001645 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001646
1647 return *holder;
1648}
1649
1650
lrn@chromium.org303ada72010-10-27 09:33:13 +00001651static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001652 // Returns a real global receiver, not one of builtins object.
1653 Context* global_context = Top::context()->global()->global_context();
1654 return global_context->global()->global_receiver();
1655}
1656
1657
lrn@chromium.org303ada72010-10-27 09:33:13 +00001658static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001659 HandleScope scope;
1660 ASSERT(args.length() == 4);
1661 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1662 int index = Smi::cast(args[1])->value();
1663 Handle<String> pattern = args.at<String>(2);
1664 Handle<String> flags = args.at<String>(3);
1665
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001666 // Get the RegExp function from the context in the literals array.
1667 // This is the RegExp function from the context in which the
1668 // function was created. We do not use the RegExp function from the
1669 // current global context because this might be the RegExp function
1670 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001671 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001672 Handle<JSFunction>(
1673 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001674 // Compute the regular expression literal.
1675 bool has_pending_exception;
1676 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001677 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1678 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679 if (has_pending_exception) {
1680 ASSERT(Top::has_pending_exception());
1681 return Failure::Exception();
1682 }
1683 literals->set(index, *regexp);
1684 return *regexp;
1685}
1686
1687
lrn@chromium.org303ada72010-10-27 09:33:13 +00001688static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689 NoHandleAllocation ha;
1690 ASSERT(args.length() == 1);
1691
1692 CONVERT_CHECKED(JSFunction, f, args[0]);
1693 return f->shared()->name();
1694}
1695
1696
lrn@chromium.org303ada72010-10-27 09:33:13 +00001697static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001698 NoHandleAllocation ha;
1699 ASSERT(args.length() == 2);
1700
1701 CONVERT_CHECKED(JSFunction, f, args[0]);
1702 CONVERT_CHECKED(String, name, args[1]);
1703 f->shared()->set_name(name);
1704 return Heap::undefined_value();
1705}
1706
1707
lrn@chromium.org303ada72010-10-27 09:33:13 +00001708static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001709 NoHandleAllocation ha;
1710 ASSERT(args.length() == 1);
1711
1712 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001713 Object* obj;
1714 { MaybeObject* maybe_obj = f->RemovePrototype();
1715 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1716 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001717
1718 return Heap::undefined_value();
1719}
1720
1721
lrn@chromium.org303ada72010-10-27 09:33:13 +00001722static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 HandleScope scope;
1724 ASSERT(args.length() == 1);
1725
1726 CONVERT_CHECKED(JSFunction, fun, args[0]);
1727 Handle<Object> script = Handle<Object>(fun->shared()->script());
1728 if (!script->IsScript()) return Heap::undefined_value();
1729
1730 return *GetScriptWrapper(Handle<Script>::cast(script));
1731}
1732
1733
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001735 NoHandleAllocation ha;
1736 ASSERT(args.length() == 1);
1737
1738 CONVERT_CHECKED(JSFunction, f, args[0]);
1739 return f->shared()->GetSourceCode();
1740}
1741
1742
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001744 NoHandleAllocation ha;
1745 ASSERT(args.length() == 1);
1746
1747 CONVERT_CHECKED(JSFunction, fun, args[0]);
1748 int pos = fun->shared()->start_position();
1749 return Smi::FromInt(pos);
1750}
1751
1752
lrn@chromium.org303ada72010-10-27 09:33:13 +00001753static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001754 ASSERT(args.length() == 2);
1755
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001756 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001757 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1758
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001759 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1760
1761 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001762 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001763}
1764
1765
1766
lrn@chromium.org303ada72010-10-27 09:33:13 +00001767static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 NoHandleAllocation ha;
1769 ASSERT(args.length() == 2);
1770
1771 CONVERT_CHECKED(JSFunction, fun, args[0]);
1772 CONVERT_CHECKED(String, name, args[1]);
1773 fun->SetInstanceClassName(name);
1774 return Heap::undefined_value();
1775}
1776
1777
lrn@chromium.org303ada72010-10-27 09:33:13 +00001778static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001779 NoHandleAllocation ha;
1780 ASSERT(args.length() == 2);
1781
1782 CONVERT_CHECKED(JSFunction, fun, args[0]);
1783 CONVERT_CHECKED(Smi, length, args[1]);
1784 fun->shared()->set_length(length->value());
1785 return length;
1786}
1787
1788
lrn@chromium.org303ada72010-10-27 09:33:13 +00001789static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001790 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001791 ASSERT(args.length() == 2);
1792
1793 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001794 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001795 Object* obj;
1796 { MaybeObject* maybe_obj =
1797 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1798 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001800 return args[0]; // return TOS
1801}
1802
1803
lrn@chromium.org303ada72010-10-27 09:33:13 +00001804static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001805 NoHandleAllocation ha;
1806 ASSERT(args.length() == 1);
1807
1808 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001809 return f->shared()->IsApiFunction() ? Heap::true_value()
1810 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001811}
1812
lrn@chromium.org303ada72010-10-27 09:33:13 +00001813static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001814 NoHandleAllocation ha;
1815 ASSERT(args.length() == 1);
1816
1817 CONVERT_CHECKED(JSFunction, f, args[0]);
1818 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1819}
1820
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001821
lrn@chromium.org303ada72010-10-27 09:33:13 +00001822static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001823 HandleScope scope;
1824 ASSERT(args.length() == 2);
1825
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001826 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827 Handle<Object> code = args.at<Object>(1);
1828
1829 Handle<Context> context(target->context());
1830
1831 if (!code->IsNull()) {
1832 RUNTIME_ASSERT(code->IsJSFunction());
1833 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001834 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001835
1836 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837 return Failure::Exception();
1838 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001839 // Since we don't store the source for this we should never
1840 // optimize this.
1841 shared->code()->set_optimizable(false);
1842
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001843 // Set the code, scope info, formal parameter count,
1844 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001845 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001846 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001847 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001848 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001849 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001850 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001851 // Set the source code of the target function to undefined.
1852 // SetCode is only used for built-in constructors like String,
1853 // Array, and Object, and some web code
1854 // doesn't like seeing source code for constructors.
1855 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001856 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001857 // Clear the optimization hints related to the compiled code as these are no
1858 // longer valid when the code is overwritten.
1859 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001860 context = Handle<Context>(fun->context());
1861
1862 // Make sure we get a fresh copy of the literal vector to avoid
1863 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001864 int number_of_literals = fun->NumberOfLiterals();
1865 Handle<FixedArray> literals =
1866 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001867 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001868 // Insert the object, regexp and array functions in the literals
1869 // array prefix. These are the functions that will be used when
1870 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001871 literals->set(JSFunction::kLiteralGlobalContextIndex,
1872 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001873 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001874 // It's okay to skip the write barrier here because the literals
1875 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001876 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001877 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 }
1879
1880 target->set_context(*context);
1881 return *target;
1882}
1883
1884
lrn@chromium.org303ada72010-10-27 09:33:13 +00001885static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001886 HandleScope scope;
1887 ASSERT(args.length() == 2);
1888 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1889 CONVERT_SMI_CHECKED(num, args[1]);
1890 RUNTIME_ASSERT(num >= 0);
1891 SetExpectedNofProperties(function, num);
1892 return Heap::undefined_value();
1893}
1894
1895
lrn@chromium.org303ada72010-10-27 09:33:13 +00001896MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001897 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001898 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001899 if (code <= 0xffff) {
1900 return Heap::LookupSingleCharacterStringFromCode(code);
1901 }
1902 }
1903 return Heap::empty_string();
1904}
1905
1906
lrn@chromium.org303ada72010-10-27 09:33:13 +00001907static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908 NoHandleAllocation ha;
1909 ASSERT(args.length() == 2);
1910
1911 CONVERT_CHECKED(String, subject, args[0]);
1912 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001913 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001915 uint32_t i = 0;
1916 if (index->IsSmi()) {
1917 int value = Smi::cast(index)->value();
1918 if (value < 0) return Heap::nan_value();
1919 i = value;
1920 } else {
1921 ASSERT(index->IsHeapNumber());
1922 double value = HeapNumber::cast(index)->value();
1923 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001924 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001925
1926 // Flatten the string. If someone wants to get a char at an index
1927 // in a cons string, it is likely that more indices will be
1928 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001929 Object* flat;
1930 { MaybeObject* maybe_flat = subject->TryFlatten();
1931 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1932 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001933 subject = String::cast(flat);
1934
1935 if (i >= static_cast<uint32_t>(subject->length())) {
1936 return Heap::nan_value();
1937 }
1938
1939 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001940}
1941
1942
lrn@chromium.org303ada72010-10-27 09:33:13 +00001943static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001944 NoHandleAllocation ha;
1945 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001946 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947}
1948
lrn@chromium.org25156de2010-04-06 13:10:27 +00001949
1950class FixedArrayBuilder {
1951 public:
1952 explicit FixedArrayBuilder(int initial_capacity)
1953 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1954 length_(0) {
1955 // Require a non-zero initial size. Ensures that doubling the size to
1956 // extend the array will work.
1957 ASSERT(initial_capacity > 0);
1958 }
1959
1960 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1961 : array_(backing_store),
1962 length_(0) {
1963 // Require a non-zero initial size. Ensures that doubling the size to
1964 // extend the array will work.
1965 ASSERT(backing_store->length() > 0);
1966 }
1967
1968 bool HasCapacity(int elements) {
1969 int length = array_->length();
1970 int required_length = length_ + elements;
1971 return (length >= required_length);
1972 }
1973
1974 void EnsureCapacity(int elements) {
1975 int length = array_->length();
1976 int required_length = length_ + elements;
1977 if (length < required_length) {
1978 int new_length = length;
1979 do {
1980 new_length *= 2;
1981 } while (new_length < required_length);
1982 Handle<FixedArray> extended_array =
1983 Factory::NewFixedArrayWithHoles(new_length);
1984 array_->CopyTo(0, *extended_array, 0, length_);
1985 array_ = extended_array;
1986 }
1987 }
1988
1989 void Add(Object* value) {
1990 ASSERT(length_ < capacity());
1991 array_->set(length_, value);
1992 length_++;
1993 }
1994
1995 void Add(Smi* value) {
1996 ASSERT(length_ < capacity());
1997 array_->set(length_, value);
1998 length_++;
1999 }
2000
2001 Handle<FixedArray> array() {
2002 return array_;
2003 }
2004
2005 int length() {
2006 return length_;
2007 }
2008
2009 int capacity() {
2010 return array_->length();
2011 }
2012
2013 Handle<JSArray> ToJSArray() {
2014 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
2015 result_array->set_length(Smi::FromInt(length_));
2016 return result_array;
2017 }
2018
2019 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2020 target_array->set_elements(*array_);
2021 target_array->set_length(Smi::FromInt(length_));
2022 return target_array;
2023 }
2024
2025 private:
2026 Handle<FixedArray> array_;
2027 int length_;
2028};
2029
2030
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002031// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002032const int kStringBuilderConcatHelperLengthBits = 11;
2033const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002034
2035template <typename schar>
2036static inline void StringBuilderConcatHelper(String*,
2037 schar*,
2038 FixedArray*,
2039 int);
2040
lrn@chromium.org25156de2010-04-06 13:10:27 +00002041typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2042 StringBuilderSubstringLength;
2043typedef BitField<int,
2044 kStringBuilderConcatHelperLengthBits,
2045 kStringBuilderConcatHelperPositionBits>
2046 StringBuilderSubstringPosition;
2047
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002048
2049class ReplacementStringBuilder {
2050 public:
2051 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00002052 : array_builder_(estimated_part_count),
2053 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002054 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002055 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002056 // Require a non-zero initial size. Ensures that doubling the size to
2057 // extend the array will work.
2058 ASSERT(estimated_part_count > 0);
2059 }
2060
lrn@chromium.org25156de2010-04-06 13:10:27 +00002061 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2062 int from,
2063 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002064 ASSERT(from >= 0);
2065 int length = to - from;
2066 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002067 if (StringBuilderSubstringLength::is_valid(length) &&
2068 StringBuilderSubstringPosition::is_valid(from)) {
2069 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2070 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002071 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002072 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002073 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002074 builder->Add(Smi::FromInt(-length));
2075 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002076 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002077 }
2078
2079
2080 void EnsureCapacity(int elements) {
2081 array_builder_.EnsureCapacity(elements);
2082 }
2083
2084
2085 void AddSubjectSlice(int from, int to) {
2086 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002087 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002088 }
2089
2090
2091 void AddString(Handle<String> string) {
2092 int length = string->length();
2093 ASSERT(length > 0);
2094 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002095 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002096 is_ascii_ = false;
2097 }
2098 IncrementCharacterCount(length);
2099 }
2100
2101
2102 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002103 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002104 return Factory::empty_string();
2105 }
2106
2107 Handle<String> joined_string;
2108 if (is_ascii_) {
2109 joined_string = NewRawAsciiString(character_count_);
2110 AssertNoAllocation no_alloc;
2111 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2112 char* char_buffer = seq->GetChars();
2113 StringBuilderConcatHelper(*subject_,
2114 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002115 *array_builder_.array(),
2116 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002117 } else {
2118 // Non-ASCII.
2119 joined_string = NewRawTwoByteString(character_count_);
2120 AssertNoAllocation no_alloc;
2121 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2122 uc16* char_buffer = seq->GetChars();
2123 StringBuilderConcatHelper(*subject_,
2124 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002125 *array_builder_.array(),
2126 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002127 }
2128 return joined_string;
2129 }
2130
2131
2132 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002133 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002134 V8::FatalProcessOutOfMemory("String.replace result too large.");
2135 }
2136 character_count_ += by;
2137 }
2138
lrn@chromium.org25156de2010-04-06 13:10:27 +00002139 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002140 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002141 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002142
lrn@chromium.org25156de2010-04-06 13:10:27 +00002143 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002144 Handle<String> NewRawAsciiString(int size) {
2145 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2146 }
2147
2148
2149 Handle<String> NewRawTwoByteString(int size) {
2150 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2151 }
2152
2153
2154 void AddElement(Object* element) {
2155 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002156 ASSERT(array_builder_.capacity() > array_builder_.length());
2157 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002158 }
2159
lrn@chromium.org25156de2010-04-06 13:10:27 +00002160 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002161 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002162 int character_count_;
2163 bool is_ascii_;
2164};
2165
2166
2167class CompiledReplacement {
2168 public:
2169 CompiledReplacement()
2170 : parts_(1), replacement_substrings_(0) {}
2171
2172 void Compile(Handle<String> replacement,
2173 int capture_count,
2174 int subject_length);
2175
2176 void Apply(ReplacementStringBuilder* builder,
2177 int match_from,
2178 int match_to,
2179 Handle<JSArray> last_match_info);
2180
2181 // Number of distinct parts of the replacement pattern.
2182 int parts() {
2183 return parts_.length();
2184 }
2185 private:
2186 enum PartType {
2187 SUBJECT_PREFIX = 1,
2188 SUBJECT_SUFFIX,
2189 SUBJECT_CAPTURE,
2190 REPLACEMENT_SUBSTRING,
2191 REPLACEMENT_STRING,
2192
2193 NUMBER_OF_PART_TYPES
2194 };
2195
2196 struct ReplacementPart {
2197 static inline ReplacementPart SubjectMatch() {
2198 return ReplacementPart(SUBJECT_CAPTURE, 0);
2199 }
2200 static inline ReplacementPart SubjectCapture(int capture_index) {
2201 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2202 }
2203 static inline ReplacementPart SubjectPrefix() {
2204 return ReplacementPart(SUBJECT_PREFIX, 0);
2205 }
2206 static inline ReplacementPart SubjectSuffix(int subject_length) {
2207 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2208 }
2209 static inline ReplacementPart ReplacementString() {
2210 return ReplacementPart(REPLACEMENT_STRING, 0);
2211 }
2212 static inline ReplacementPart ReplacementSubString(int from, int to) {
2213 ASSERT(from >= 0);
2214 ASSERT(to > from);
2215 return ReplacementPart(-from, to);
2216 }
2217
2218 // If tag <= 0 then it is the negation of a start index of a substring of
2219 // the replacement pattern, otherwise it's a value from PartType.
2220 ReplacementPart(int tag, int data)
2221 : tag(tag), data(data) {
2222 // Must be non-positive or a PartType value.
2223 ASSERT(tag < NUMBER_OF_PART_TYPES);
2224 }
2225 // Either a value of PartType or a non-positive number that is
2226 // the negation of an index into the replacement string.
2227 int tag;
2228 // The data value's interpretation depends on the value of tag:
2229 // tag == SUBJECT_PREFIX ||
2230 // tag == SUBJECT_SUFFIX: data is unused.
2231 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2232 // tag == REPLACEMENT_SUBSTRING ||
2233 // tag == REPLACEMENT_STRING: data is index into array of substrings
2234 // of the replacement string.
2235 // tag <= 0: Temporary representation of the substring of the replacement
2236 // string ranging over -tag .. data.
2237 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2238 // substring objects.
2239 int data;
2240 };
2241
2242 template<typename Char>
2243 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2244 Vector<Char> characters,
2245 int capture_count,
2246 int subject_length) {
2247 int length = characters.length();
2248 int last = 0;
2249 for (int i = 0; i < length; i++) {
2250 Char c = characters[i];
2251 if (c == '$') {
2252 int next_index = i + 1;
2253 if (next_index == length) { // No next character!
2254 break;
2255 }
2256 Char c2 = characters[next_index];
2257 switch (c2) {
2258 case '$':
2259 if (i > last) {
2260 // There is a substring before. Include the first "$".
2261 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2262 last = next_index + 1; // Continue after the second "$".
2263 } else {
2264 // Let the next substring start with the second "$".
2265 last = next_index;
2266 }
2267 i = next_index;
2268 break;
2269 case '`':
2270 if (i > last) {
2271 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2272 }
2273 parts->Add(ReplacementPart::SubjectPrefix());
2274 i = next_index;
2275 last = i + 1;
2276 break;
2277 case '\'':
2278 if (i > last) {
2279 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2280 }
2281 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2282 i = next_index;
2283 last = i + 1;
2284 break;
2285 case '&':
2286 if (i > last) {
2287 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2288 }
2289 parts->Add(ReplacementPart::SubjectMatch());
2290 i = next_index;
2291 last = i + 1;
2292 break;
2293 case '0':
2294 case '1':
2295 case '2':
2296 case '3':
2297 case '4':
2298 case '5':
2299 case '6':
2300 case '7':
2301 case '8':
2302 case '9': {
2303 int capture_ref = c2 - '0';
2304 if (capture_ref > capture_count) {
2305 i = next_index;
2306 continue;
2307 }
2308 int second_digit_index = next_index + 1;
2309 if (second_digit_index < length) {
2310 // Peek ahead to see if we have two digits.
2311 Char c3 = characters[second_digit_index];
2312 if ('0' <= c3 && c3 <= '9') { // Double digits.
2313 int double_digit_ref = capture_ref * 10 + c3 - '0';
2314 if (double_digit_ref <= capture_count) {
2315 next_index = second_digit_index;
2316 capture_ref = double_digit_ref;
2317 }
2318 }
2319 }
2320 if (capture_ref > 0) {
2321 if (i > last) {
2322 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2323 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002324 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002325 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2326 last = next_index + 1;
2327 }
2328 i = next_index;
2329 break;
2330 }
2331 default:
2332 i = next_index;
2333 break;
2334 }
2335 }
2336 }
2337 if (length > last) {
2338 if (last == 0) {
2339 parts->Add(ReplacementPart::ReplacementString());
2340 } else {
2341 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2342 }
2343 }
2344 }
2345
2346 ZoneList<ReplacementPart> parts_;
2347 ZoneList<Handle<String> > replacement_substrings_;
2348};
2349
2350
2351void CompiledReplacement::Compile(Handle<String> replacement,
2352 int capture_count,
2353 int subject_length) {
2354 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002355 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002356 AssertNoAllocation no_alloc;
2357 ParseReplacementPattern(&parts_,
2358 replacement->ToAsciiVector(),
2359 capture_count,
2360 subject_length);
2361 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002362 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363 AssertNoAllocation no_alloc;
2364
2365 ParseReplacementPattern(&parts_,
2366 replacement->ToUC16Vector(),
2367 capture_count,
2368 subject_length);
2369 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002370 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002371 int substring_index = 0;
2372 for (int i = 0, n = parts_.length(); i < n; i++) {
2373 int tag = parts_[i].tag;
2374 if (tag <= 0) { // A replacement string slice.
2375 int from = -tag;
2376 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002377 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002378 parts_[i].tag = REPLACEMENT_SUBSTRING;
2379 parts_[i].data = substring_index;
2380 substring_index++;
2381 } else if (tag == REPLACEMENT_STRING) {
2382 replacement_substrings_.Add(replacement);
2383 parts_[i].data = substring_index;
2384 substring_index++;
2385 }
2386 }
2387}
2388
2389
2390void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2391 int match_from,
2392 int match_to,
2393 Handle<JSArray> last_match_info) {
2394 for (int i = 0, n = parts_.length(); i < n; i++) {
2395 ReplacementPart part = parts_[i];
2396 switch (part.tag) {
2397 case SUBJECT_PREFIX:
2398 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2399 break;
2400 case SUBJECT_SUFFIX: {
2401 int subject_length = part.data;
2402 if (match_to < subject_length) {
2403 builder->AddSubjectSlice(match_to, subject_length);
2404 }
2405 break;
2406 }
2407 case SUBJECT_CAPTURE: {
2408 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002409 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002410 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2411 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2412 if (from >= 0 && to > from) {
2413 builder->AddSubjectSlice(from, to);
2414 }
2415 break;
2416 }
2417 case REPLACEMENT_SUBSTRING:
2418 case REPLACEMENT_STRING:
2419 builder->AddString(replacement_substrings_[part.data]);
2420 break;
2421 default:
2422 UNREACHABLE();
2423 }
2424 }
2425}
2426
2427
2428
lrn@chromium.org303ada72010-10-27 09:33:13 +00002429MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2430 String* subject,
2431 JSRegExp* regexp,
2432 String* replacement,
2433 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002434 ASSERT(subject->IsFlat());
2435 ASSERT(replacement->IsFlat());
2436
2437 HandleScope handles;
2438
2439 int length = subject->length();
2440 Handle<String> subject_handle(subject);
2441 Handle<JSRegExp> regexp_handle(regexp);
2442 Handle<String> replacement_handle(replacement);
2443 Handle<JSArray> last_match_info_handle(last_match_info);
2444 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2445 subject_handle,
2446 0,
2447 last_match_info_handle);
2448 if (match.is_null()) {
2449 return Failure::Exception();
2450 }
2451 if (match->IsNull()) {
2452 return *subject_handle;
2453 }
2454
2455 int capture_count = regexp_handle->CaptureCount();
2456
2457 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002458 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 CompiledReplacement compiled_replacement;
2460 compiled_replacement.Compile(replacement_handle,
2461 capture_count,
2462 length);
2463
2464 bool is_global = regexp_handle->GetFlags().is_global();
2465
2466 // Guessing the number of parts that the final result string is built
2467 // from. Global regexps can match any number of times, so we guess
2468 // conservatively.
2469 int expected_parts =
2470 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2471 ReplacementStringBuilder builder(subject_handle, expected_parts);
2472
2473 // Index of end of last match.
2474 int prev = 0;
2475
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002476 // Number of parts added by compiled replacement plus preceeding
2477 // string and possibly suffix after last match. It is possible for
2478 // all components to use two elements when encoded as two smis.
2479 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 bool matched = true;
2481 do {
2482 ASSERT(last_match_info_handle->HasFastElements());
2483 // Increase the capacity of the builder before entering local handle-scope,
2484 // so its internal buffer can safely allocate a new handle if it grows.
2485 builder.EnsureCapacity(parts_added_per_loop);
2486
2487 HandleScope loop_scope;
2488 int start, end;
2489 {
2490 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002491 FixedArray* match_info_array =
2492 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493
2494 ASSERT_EQ(capture_count * 2 + 2,
2495 RegExpImpl::GetLastCaptureCount(match_info_array));
2496 start = RegExpImpl::GetCapture(match_info_array, 0);
2497 end = RegExpImpl::GetCapture(match_info_array, 1);
2498 }
2499
2500 if (prev < start) {
2501 builder.AddSubjectSlice(prev, start);
2502 }
2503 compiled_replacement.Apply(&builder,
2504 start,
2505 end,
2506 last_match_info_handle);
2507 prev = end;
2508
2509 // Only continue checking for global regexps.
2510 if (!is_global) break;
2511
2512 // Continue from where the match ended, unless it was an empty match.
2513 int next = end;
2514 if (start == end) {
2515 next = end + 1;
2516 if (next > length) break;
2517 }
2518
2519 match = RegExpImpl::Exec(regexp_handle,
2520 subject_handle,
2521 next,
2522 last_match_info_handle);
2523 if (match.is_null()) {
2524 return Failure::Exception();
2525 }
2526 matched = !match->IsNull();
2527 } while (matched);
2528
2529 if (prev < length) {
2530 builder.AddSubjectSlice(prev, length);
2531 }
2532
2533 return *(builder.ToString());
2534}
2535
2536
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002537template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002538MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2539 String* subject,
2540 JSRegExp* regexp,
2541 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002542 ASSERT(subject->IsFlat());
2543
2544 HandleScope handles;
2545
2546 Handle<String> subject_handle(subject);
2547 Handle<JSRegExp> regexp_handle(regexp);
2548 Handle<JSArray> last_match_info_handle(last_match_info);
2549 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2550 subject_handle,
2551 0,
2552 last_match_info_handle);
2553 if (match.is_null()) return Failure::Exception();
2554 if (match->IsNull()) return *subject_handle;
2555
2556 ASSERT(last_match_info_handle->HasFastElements());
2557
2558 HandleScope loop_scope;
2559 int start, end;
2560 {
2561 AssertNoAllocation match_info_array_is_not_in_a_handle;
2562 FixedArray* match_info_array =
2563 FixedArray::cast(last_match_info_handle->elements());
2564
2565 start = RegExpImpl::GetCapture(match_info_array, 0);
2566 end = RegExpImpl::GetCapture(match_info_array, 1);
2567 }
2568
2569 int length = subject->length();
2570 int new_length = length - (end - start);
2571 if (new_length == 0) {
2572 return Heap::empty_string();
2573 }
2574 Handle<ResultSeqString> answer;
2575 if (ResultSeqString::kHasAsciiEncoding) {
2576 answer =
2577 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2578 } else {
2579 answer =
2580 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2581 }
2582
2583 // If the regexp isn't global, only match once.
2584 if (!regexp_handle->GetFlags().is_global()) {
2585 if (start > 0) {
2586 String::WriteToFlat(*subject_handle,
2587 answer->GetChars(),
2588 0,
2589 start);
2590 }
2591 if (end < length) {
2592 String::WriteToFlat(*subject_handle,
2593 answer->GetChars() + start,
2594 end,
2595 length);
2596 }
2597 return *answer;
2598 }
2599
2600 int prev = 0; // Index of end of last match.
2601 int next = 0; // Start of next search (prev unless last match was empty).
2602 int position = 0;
2603
2604 do {
2605 if (prev < start) {
2606 // Add substring subject[prev;start] to answer string.
2607 String::WriteToFlat(*subject_handle,
2608 answer->GetChars() + position,
2609 prev,
2610 start);
2611 position += start - prev;
2612 }
2613 prev = end;
2614 next = end;
2615 // Continue from where the match ended, unless it was an empty match.
2616 if (start == end) {
2617 next++;
2618 if (next > length) break;
2619 }
2620 match = RegExpImpl::Exec(regexp_handle,
2621 subject_handle,
2622 next,
2623 last_match_info_handle);
2624 if (match.is_null()) return Failure::Exception();
2625 if (match->IsNull()) break;
2626
2627 ASSERT(last_match_info_handle->HasFastElements());
2628 HandleScope loop_scope;
2629 {
2630 AssertNoAllocation match_info_array_is_not_in_a_handle;
2631 FixedArray* match_info_array =
2632 FixedArray::cast(last_match_info_handle->elements());
2633 start = RegExpImpl::GetCapture(match_info_array, 0);
2634 end = RegExpImpl::GetCapture(match_info_array, 1);
2635 }
2636 } while (true);
2637
2638 if (prev < length) {
2639 // Add substring subject[prev;length] to answer string.
2640 String::WriteToFlat(*subject_handle,
2641 answer->GetChars() + position,
2642 prev,
2643 length);
2644 position += length - prev;
2645 }
2646
2647 if (position == 0) {
2648 return Heap::empty_string();
2649 }
2650
2651 // Shorten string and fill
2652 int string_size = ResultSeqString::SizeFor(position);
2653 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2654 int delta = allocated_string_size - string_size;
2655
2656 answer->set_length(position);
2657 if (delta == 0) return *answer;
2658
2659 Address end_of_string = answer->address() + string_size;
2660 Heap::CreateFillerObjectAt(end_of_string, delta);
2661
2662 return *answer;
2663}
2664
2665
lrn@chromium.org303ada72010-10-27 09:33:13 +00002666static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002667 ASSERT(args.length() == 4);
2668
2669 CONVERT_CHECKED(String, subject, args[0]);
2670 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002671 Object* flat_subject;
2672 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2673 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2674 return maybe_flat_subject;
2675 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002676 }
2677 subject = String::cast(flat_subject);
2678 }
2679
2680 CONVERT_CHECKED(String, replacement, args[2]);
2681 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002682 Object* flat_replacement;
2683 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2684 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2685 return maybe_flat_replacement;
2686 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002687 }
2688 replacement = String::cast(flat_replacement);
2689 }
2690
2691 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2692 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2693
2694 ASSERT(last_match_info->HasFastElements());
2695
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002696 if (replacement->length() == 0) {
2697 if (subject->HasOnlyAsciiChars()) {
2698 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2699 subject, regexp, last_match_info);
2700 } else {
2701 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2702 subject, regexp, last_match_info);
2703 }
2704 }
2705
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002706 return StringReplaceRegExpWithString(subject,
2707 regexp,
2708 replacement,
2709 last_match_info);
2710}
2711
2712
ager@chromium.org7c537e22008-10-16 08:43:32 +00002713// Perform string match of pattern on subject, starting at start index.
2714// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002715// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002716int Runtime::StringMatch(Handle<String> sub,
2717 Handle<String> pat,
2718 int start_index) {
2719 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002720 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002721
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002722 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002723 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002724
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002725 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002726 if (start_index + pattern_length > subject_length) return -1;
2727
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002728 if (!sub->IsFlat()) FlattenString(sub);
2729 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002730
ager@chromium.org7c537e22008-10-16 08:43:32 +00002731 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002732 // Extract flattened substrings of cons strings before determining asciiness.
2733 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002734 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002735 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002736 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002737
ager@chromium.org7c537e22008-10-16 08:43:32 +00002738 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002739 if (seq_pat->IsAsciiRepresentation()) {
2740 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2741 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002742 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002743 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002744 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002745 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002746 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2747 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002748 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002749 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002750 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002751}
2752
2753
lrn@chromium.org303ada72010-10-27 09:33:13 +00002754static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002755 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002756 ASSERT(args.length() == 3);
2757
ager@chromium.org7c537e22008-10-16 08:43:32 +00002758 CONVERT_ARG_CHECKED(String, sub, 0);
2759 CONVERT_ARG_CHECKED(String, pat, 1);
2760
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002761 Object* index = args[2];
2762 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002763 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002764
ager@chromium.org870a0b62008-11-04 11:43:05 +00002765 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002766 int position = Runtime::StringMatch(sub, pat, start_index);
2767 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002768}
2769
2770
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002771template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002772static int StringMatchBackwards(Vector<const schar> subject,
2773 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002774 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002775 int pattern_length = pattern.length();
2776 ASSERT(pattern_length >= 1);
2777 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002778
2779 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002780 for (int i = 0; i < pattern_length; i++) {
2781 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002782 if (c > String::kMaxAsciiCharCode) {
2783 return -1;
2784 }
2785 }
2786 }
2787
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002788 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002789 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002790 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002791 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002792 while (j < pattern_length) {
2793 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002794 break;
2795 }
2796 j++;
2797 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002798 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002799 return i;
2800 }
2801 }
2802 return -1;
2803}
2804
lrn@chromium.org303ada72010-10-27 09:33:13 +00002805static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002806 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002807 ASSERT(args.length() == 3);
2808
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002809 CONVERT_ARG_CHECKED(String, sub, 0);
2810 CONVERT_ARG_CHECKED(String, pat, 1);
2811
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002812 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002813 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002814 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002815
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002816 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002817 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002818
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002819 if (start_index + pat_length > sub_length) {
2820 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002821 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002822
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002823 if (pat_length == 0) {
2824 return Smi::FromInt(start_index);
2825 }
2826
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002827 if (!sub->IsFlat()) FlattenString(sub);
2828 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002829
2830 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2831
2832 int position = -1;
2833
2834 if (pat->IsAsciiRepresentation()) {
2835 Vector<const char> pat_vector = pat->ToAsciiVector();
2836 if (sub->IsAsciiRepresentation()) {
2837 position = StringMatchBackwards(sub->ToAsciiVector(),
2838 pat_vector,
2839 start_index);
2840 } else {
2841 position = StringMatchBackwards(sub->ToUC16Vector(),
2842 pat_vector,
2843 start_index);
2844 }
2845 } else {
2846 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2847 if (sub->IsAsciiRepresentation()) {
2848 position = StringMatchBackwards(sub->ToAsciiVector(),
2849 pat_vector,
2850 start_index);
2851 } else {
2852 position = StringMatchBackwards(sub->ToUC16Vector(),
2853 pat_vector,
2854 start_index);
2855 }
2856 }
2857
2858 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002859}
2860
2861
lrn@chromium.org303ada72010-10-27 09:33:13 +00002862static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002863 NoHandleAllocation ha;
2864 ASSERT(args.length() == 2);
2865
2866 CONVERT_CHECKED(String, str1, args[0]);
2867 CONVERT_CHECKED(String, str2, args[1]);
2868
2869 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002870 int str1_length = str1->length();
2871 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002872
2873 // Decide trivial cases without flattening.
2874 if (str1_length == 0) {
2875 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2876 return Smi::FromInt(-str2_length);
2877 } else {
2878 if (str2_length == 0) return Smi::FromInt(str1_length);
2879 }
2880
2881 int end = str1_length < str2_length ? str1_length : str2_length;
2882
2883 // No need to flatten if we are going to find the answer on the first
2884 // character. At this point we know there is at least one character
2885 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002886 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887 if (d != 0) return Smi::FromInt(d);
2888
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002889 str1->TryFlatten();
2890 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891
2892 static StringInputBuffer buf1;
2893 static StringInputBuffer buf2;
2894
2895 buf1.Reset(str1);
2896 buf2.Reset(str2);
2897
2898 for (int i = 0; i < end; i++) {
2899 uint16_t char1 = buf1.GetNext();
2900 uint16_t char2 = buf2.GetNext();
2901 if (char1 != char2) return Smi::FromInt(char1 - char2);
2902 }
2903
2904 return Smi::FromInt(str1_length - str2_length);
2905}
2906
2907
lrn@chromium.org303ada72010-10-27 09:33:13 +00002908static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002909 NoHandleAllocation ha;
2910 ASSERT(args.length() == 3);
2911
2912 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002913 Object* from = args[1];
2914 Object* to = args[2];
2915 int start, end;
2916 // We have a fast integer-only case here to avoid a conversion to double in
2917 // the common case where from and to are Smis.
2918 if (from->IsSmi() && to->IsSmi()) {
2919 start = Smi::cast(from)->value();
2920 end = Smi::cast(to)->value();
2921 } else {
2922 CONVERT_DOUBLE_CHECKED(from_number, from);
2923 CONVERT_DOUBLE_CHECKED(to_number, to);
2924 start = FastD2I(from_number);
2925 end = FastD2I(to_number);
2926 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002927 RUNTIME_ASSERT(end >= start);
2928 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002929 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002930 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002931 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002932}
2933
2934
lrn@chromium.org303ada72010-10-27 09:33:13 +00002935static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002936 ASSERT_EQ(3, args.length());
2937
2938 CONVERT_ARG_CHECKED(String, subject, 0);
2939 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2940 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2941 HandleScope handles;
2942
2943 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2944
2945 if (match.is_null()) {
2946 return Failure::Exception();
2947 }
2948 if (match->IsNull()) {
2949 return Heap::null_value();
2950 }
2951 int length = subject->length();
2952
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002953 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002954 ZoneList<int> offsets(8);
2955 do {
2956 int start;
2957 int end;
2958 {
2959 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002960 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002961 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2962 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2963 }
2964 offsets.Add(start);
2965 offsets.Add(end);
2966 int index = start < end ? end : end + 1;
2967 if (index > length) break;
2968 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2969 if (match.is_null()) {
2970 return Failure::Exception();
2971 }
2972 } while (!match->IsNull());
2973 int matches = offsets.length() / 2;
2974 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2975 for (int i = 0; i < matches ; i++) {
2976 int from = offsets.at(i * 2);
2977 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002978 Handle<String> match = Factory::NewSubString(subject, from, to);
2979 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002980 }
2981 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2982 result->set_length(Smi::FromInt(matches));
2983 return *result;
2984}
2985
2986
lrn@chromium.org25156de2010-04-06 13:10:27 +00002987// Two smis before and after the match, for very long strings.
2988const int kMaxBuilderEntriesPerRegExpMatch = 5;
2989
2990
2991static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2992 Handle<JSArray> last_match_info,
2993 int match_start,
2994 int match_end) {
2995 // Fill last_match_info with a single capture.
2996 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2997 AssertNoAllocation no_gc;
2998 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2999 RegExpImpl::SetLastCaptureCount(elements, 2);
3000 RegExpImpl::SetLastInput(elements, *subject);
3001 RegExpImpl::SetLastSubject(elements, *subject);
3002 RegExpImpl::SetCapture(elements, 0, match_start);
3003 RegExpImpl::SetCapture(elements, 1, match_end);
3004}
3005
3006
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003007template <typename SubjectChar, typename PatternChar>
3008static bool SearchStringMultiple(Vector<const SubjectChar> subject,
3009 Vector<const PatternChar> pattern,
3010 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003011 FixedArrayBuilder* builder,
3012 int* match_pos) {
3013 int pos = *match_pos;
3014 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003015 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003016 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003017 StringSearch<PatternChar, SubjectChar> search(pattern);
3018 while (pos <= max_search_start) {
3019 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3020 *match_pos = pos;
3021 return false;
3022 }
3023 // Position of end of previous match.
3024 int match_end = pos + pattern_length;
3025 int new_pos = search.Search(subject, match_end);
3026 if (new_pos >= 0) {
3027 // A match.
3028 if (new_pos > match_end) {
3029 ReplacementStringBuilder::AddSubjectSlice(builder,
3030 match_end,
3031 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003032 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003033 pos = new_pos;
3034 builder->Add(pattern_string);
3035 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003036 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003037 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003038 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003039
lrn@chromium.org25156de2010-04-06 13:10:27 +00003040 if (pos < max_search_start) {
3041 ReplacementStringBuilder::AddSubjectSlice(builder,
3042 pos + pattern_length,
3043 subject_length);
3044 }
3045 *match_pos = pos;
3046 return true;
3047}
3048
3049
3050static bool SearchStringMultiple(Handle<String> subject,
3051 Handle<String> pattern,
3052 Handle<JSArray> last_match_info,
3053 FixedArrayBuilder* builder) {
3054 ASSERT(subject->IsFlat());
3055 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003056
3057 // Treating as if a previous match was before first character.
3058 int match_pos = -pattern->length();
3059
3060 for (;;) { // Break when search complete.
3061 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3062 AssertNoAllocation no_gc;
3063 if (subject->IsAsciiRepresentation()) {
3064 Vector<const char> subject_vector = subject->ToAsciiVector();
3065 if (pattern->IsAsciiRepresentation()) {
3066 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003067 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003068 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003069 builder,
3070 &match_pos)) break;
3071 } else {
3072 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003073 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003074 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003075 builder,
3076 &match_pos)) break;
3077 }
3078 } else {
3079 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3080 if (pattern->IsAsciiRepresentation()) {
3081 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003082 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003083 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003084 builder,
3085 &match_pos)) break;
3086 } else {
3087 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003088 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003089 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003090 builder,
3091 &match_pos)) break;
3092 }
3093 }
3094 }
3095
3096 if (match_pos >= 0) {
3097 SetLastMatchInfoNoCaptures(subject,
3098 last_match_info,
3099 match_pos,
3100 match_pos + pattern->length());
3101 return true;
3102 }
3103 return false; // No matches at all.
3104}
3105
3106
3107static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3108 Handle<String> subject,
3109 Handle<JSRegExp> regexp,
3110 Handle<JSArray> last_match_array,
3111 FixedArrayBuilder* builder) {
3112 ASSERT(subject->IsFlat());
3113 int match_start = -1;
3114 int match_end = 0;
3115 int pos = 0;
3116 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3117 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3118
3119 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003120 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003121 int subject_length = subject->length();
3122
3123 for (;;) { // Break on failure, return on exception.
3124 RegExpImpl::IrregexpResult result =
3125 RegExpImpl::IrregexpExecOnce(regexp,
3126 subject,
3127 pos,
3128 register_vector);
3129 if (result == RegExpImpl::RE_SUCCESS) {
3130 match_start = register_vector[0];
3131 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3132 if (match_end < match_start) {
3133 ReplacementStringBuilder::AddSubjectSlice(builder,
3134 match_end,
3135 match_start);
3136 }
3137 match_end = register_vector[1];
3138 HandleScope loop_scope;
3139 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3140 if (match_start != match_end) {
3141 pos = match_end;
3142 } else {
3143 pos = match_end + 1;
3144 if (pos > subject_length) break;
3145 }
3146 } else if (result == RegExpImpl::RE_FAILURE) {
3147 break;
3148 } else {
3149 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3150 return result;
3151 }
3152 }
3153
3154 if (match_start >= 0) {
3155 if (match_end < subject_length) {
3156 ReplacementStringBuilder::AddSubjectSlice(builder,
3157 match_end,
3158 subject_length);
3159 }
3160 SetLastMatchInfoNoCaptures(subject,
3161 last_match_array,
3162 match_start,
3163 match_end);
3164 return RegExpImpl::RE_SUCCESS;
3165 } else {
3166 return RegExpImpl::RE_FAILURE; // No matches at all.
3167 }
3168}
3169
3170
3171static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3172 Handle<String> subject,
3173 Handle<JSRegExp> regexp,
3174 Handle<JSArray> last_match_array,
3175 FixedArrayBuilder* builder) {
3176
3177 ASSERT(subject->IsFlat());
3178 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3179 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3180
3181 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003182 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003183
3184 RegExpImpl::IrregexpResult result =
3185 RegExpImpl::IrregexpExecOnce(regexp,
3186 subject,
3187 0,
3188 register_vector);
3189
3190 int capture_count = regexp->CaptureCount();
3191 int subject_length = subject->length();
3192
3193 // Position to search from.
3194 int pos = 0;
3195 // End of previous match. Differs from pos if match was empty.
3196 int match_end = 0;
3197 if (result == RegExpImpl::RE_SUCCESS) {
3198 // Need to keep a copy of the previous match for creating last_match_info
3199 // at the end, so we have two vectors that we swap between.
3200 OffsetsVector registers2(required_registers);
3201 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3202
3203 do {
3204 int match_start = register_vector[0];
3205 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3206 if (match_end < match_start) {
3207 ReplacementStringBuilder::AddSubjectSlice(builder,
3208 match_end,
3209 match_start);
3210 }
3211 match_end = register_vector[1];
3212
3213 {
3214 // Avoid accumulating new handles inside loop.
3215 HandleScope temp_scope;
3216 // Arguments array to replace function is match, captures, index and
3217 // subject, i.e., 3 + capture count in total.
3218 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003219 Handle<String> match = Factory::NewSubString(subject,
3220 match_start,
3221 match_end);
3222 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003223 for (int i = 1; i <= capture_count; i++) {
3224 int start = register_vector[i * 2];
3225 if (start >= 0) {
3226 int end = register_vector[i * 2 + 1];
3227 ASSERT(start <= end);
3228 Handle<String> substring = Factory::NewSubString(subject,
3229 start,
3230 end);
3231 elements->set(i, *substring);
3232 } else {
3233 ASSERT(register_vector[i * 2 + 1] < 0);
3234 elements->set(i, Heap::undefined_value());
3235 }
3236 }
3237 elements->set(capture_count + 1, Smi::FromInt(match_start));
3238 elements->set(capture_count + 2, *subject);
3239 builder->Add(*Factory::NewJSArrayWithElements(elements));
3240 }
3241 // Swap register vectors, so the last successful match is in
3242 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003243 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003244 prev_register_vector = register_vector;
3245 register_vector = tmp;
3246
3247 if (match_end > match_start) {
3248 pos = match_end;
3249 } else {
3250 pos = match_end + 1;
3251 if (pos > subject_length) {
3252 break;
3253 }
3254 }
3255
3256 result = RegExpImpl::IrregexpExecOnce(regexp,
3257 subject,
3258 pos,
3259 register_vector);
3260 } while (result == RegExpImpl::RE_SUCCESS);
3261
3262 if (result != RegExpImpl::RE_EXCEPTION) {
3263 // Finished matching, with at least one match.
3264 if (match_end < subject_length) {
3265 ReplacementStringBuilder::AddSubjectSlice(builder,
3266 match_end,
3267 subject_length);
3268 }
3269
3270 int last_match_capture_count = (capture_count + 1) * 2;
3271 int last_match_array_size =
3272 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3273 last_match_array->EnsureSize(last_match_array_size);
3274 AssertNoAllocation no_gc;
3275 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3276 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3277 RegExpImpl::SetLastSubject(elements, *subject);
3278 RegExpImpl::SetLastInput(elements, *subject);
3279 for (int i = 0; i < last_match_capture_count; i++) {
3280 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3281 }
3282 return RegExpImpl::RE_SUCCESS;
3283 }
3284 }
3285 // No matches at all, return failure or exception result directly.
3286 return result;
3287}
3288
3289
lrn@chromium.org303ada72010-10-27 09:33:13 +00003290static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003291 ASSERT(args.length() == 4);
3292 HandleScope handles;
3293
3294 CONVERT_ARG_CHECKED(String, subject, 1);
3295 if (!subject->IsFlat()) { FlattenString(subject); }
3296 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3297 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3298 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3299
3300 ASSERT(last_match_info->HasFastElements());
3301 ASSERT(regexp->GetFlags().is_global());
3302 Handle<FixedArray> result_elements;
3303 if (result_array->HasFastElements()) {
3304 result_elements =
3305 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3306 } else {
3307 result_elements = Factory::NewFixedArrayWithHoles(16);
3308 }
3309 FixedArrayBuilder builder(result_elements);
3310
3311 if (regexp->TypeTag() == JSRegExp::ATOM) {
3312 Handle<String> pattern(
3313 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003314 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003315 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3316 return *builder.ToJSArray(result_array);
3317 }
3318 return Heap::null_value();
3319 }
3320
3321 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3322
3323 RegExpImpl::IrregexpResult result;
3324 if (regexp->CaptureCount() == 0) {
3325 result = SearchRegExpNoCaptureMultiple(subject,
3326 regexp,
3327 last_match_info,
3328 &builder);
3329 } else {
3330 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3331 }
3332 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3333 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3334 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3335 return Failure::Exception();
3336}
3337
3338
lrn@chromium.org303ada72010-10-27 09:33:13 +00003339static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 NoHandleAllocation ha;
3341 ASSERT(args.length() == 2);
3342
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003343 // Fast case where the result is a one character string.
3344 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3345 int value = Smi::cast(args[0])->value();
3346 int radix = Smi::cast(args[1])->value();
3347 if (value >= 0 && value < radix) {
3348 RUNTIME_ASSERT(radix <= 36);
3349 // Character array used for conversion.
3350 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3351 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3352 }
3353 }
3354
3355 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003356 CONVERT_DOUBLE_CHECKED(value, args[0]);
3357 if (isnan(value)) {
3358 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3359 }
3360 if (isinf(value)) {
3361 if (value < 0) {
3362 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3363 }
3364 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3365 }
3366 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3367 int radix = FastD2I(radix_number);
3368 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3369 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003370 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003371 DeleteArray(str);
3372 return result;
3373}
3374
3375
lrn@chromium.org303ada72010-10-27 09:33:13 +00003376static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003377 NoHandleAllocation ha;
3378 ASSERT(args.length() == 2);
3379
3380 CONVERT_DOUBLE_CHECKED(value, args[0]);
3381 if (isnan(value)) {
3382 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3383 }
3384 if (isinf(value)) {
3385 if (value < 0) {
3386 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3387 }
3388 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3389 }
3390 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3391 int f = FastD2I(f_number);
3392 RUNTIME_ASSERT(f >= 0);
3393 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003394 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003395 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003396 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003397}
3398
3399
lrn@chromium.org303ada72010-10-27 09:33:13 +00003400static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 NoHandleAllocation ha;
3402 ASSERT(args.length() == 2);
3403
3404 CONVERT_DOUBLE_CHECKED(value, args[0]);
3405 if (isnan(value)) {
3406 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3407 }
3408 if (isinf(value)) {
3409 if (value < 0) {
3410 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3411 }
3412 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3413 }
3414 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3415 int f = FastD2I(f_number);
3416 RUNTIME_ASSERT(f >= -1 && f <= 20);
3417 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003418 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003420 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003421}
3422
3423
lrn@chromium.org303ada72010-10-27 09:33:13 +00003424static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003425 NoHandleAllocation ha;
3426 ASSERT(args.length() == 2);
3427
3428 CONVERT_DOUBLE_CHECKED(value, args[0]);
3429 if (isnan(value)) {
3430 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3431 }
3432 if (isinf(value)) {
3433 if (value < 0) {
3434 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3435 }
3436 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3437 }
3438 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3439 int f = FastD2I(f_number);
3440 RUNTIME_ASSERT(f >= 1 && f <= 21);
3441 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003442 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003443 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003444 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003445}
3446
3447
3448// Returns a single character string where first character equals
3449// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003450static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003451 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003452 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003453 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003454 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003455 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003456 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457}
3458
3459
lrn@chromium.org303ada72010-10-27 09:33:13 +00003460MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3461 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003462 // Handle [] indexing on Strings
3463 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003464 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3465 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466 }
3467
3468 // Handle [] indexing on String objects
3469 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003470 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3471 Handle<Object> result =
3472 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3473 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003474 }
3475
3476 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003477 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003478 return prototype->GetElement(index);
3479 }
3480
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003481 return GetElement(object, index);
3482}
3483
3484
lrn@chromium.org303ada72010-10-27 09:33:13 +00003485MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003486 return object->GetElement(index);
3487}
3488
3489
lrn@chromium.org303ada72010-10-27 09:33:13 +00003490MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3491 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003492 HandleScope scope;
3493
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003494 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003495 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003496 Handle<Object> error =
3497 Factory::NewTypeError("non_object_property_load",
3498 HandleVector(args, 2));
3499 return Top::Throw(*error);
3500 }
3501
3502 // Check if the given key is an array index.
3503 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003504 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003505 return GetElementOrCharAt(object, index);
3506 }
3507
3508 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003509 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003510 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003511 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003512 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513 bool has_pending_exception = false;
3514 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003515 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003516 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003517 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003518 }
3519
ager@chromium.org32912102009-01-16 10:38:43 +00003520 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 // the element if so.
3522 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003523 return GetElementOrCharAt(object, index);
3524 } else {
3525 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003526 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003527 }
3528}
3529
3530
lrn@chromium.org303ada72010-10-27 09:33:13 +00003531static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003532 NoHandleAllocation ha;
3533 ASSERT(args.length() == 2);
3534
3535 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003536 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537
3538 return Runtime::GetObjectProperty(object, key);
3539}
3540
3541
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003542// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003543static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003544 NoHandleAllocation ha;
3545 ASSERT(args.length() == 2);
3546
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003547 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003548 // itself.
3549 //
3550 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003551 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003552 // global proxy object never has properties. This is the case
3553 // because the global proxy object forwards everything to its hidden
3554 // prototype including local lookups.
3555 //
3556 // Additionally, we need to make sure that we do not cache results
3557 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003558 if (args[0]->IsJSObject() &&
3559 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003560 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003561 args[1]->IsString()) {
3562 JSObject* receiver = JSObject::cast(args[0]);
3563 String* key = String::cast(args[1]);
3564 if (receiver->HasFastProperties()) {
3565 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003566 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003567 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3568 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003569 Object* value = receiver->FastPropertyAt(offset);
3570 return value->IsTheHole() ? Heap::undefined_value() : value;
3571 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003572 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003573 LookupResult result;
3574 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003575 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003576 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003577 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003578 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003579 }
3580 } else {
3581 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003582 StringDictionary* dictionary = receiver->property_dictionary();
3583 int entry = dictionary->FindEntry(key);
3584 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003585 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003586 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003587 if (!receiver->IsGlobalObject()) return value;
3588 value = JSGlobalPropertyCell::cast(value)->value();
3589 if (!value->IsTheHole()) return value;
3590 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003591 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003592 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003593 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3594 // Fast case for string indexing using [] with a smi index.
3595 HandleScope scope;
3596 Handle<String> str = args.at<String>(0);
3597 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003598 if (index >= 0 && index < str->length()) {
3599 Handle<Object> result = GetCharAt(str, index);
3600 return *result;
3601 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003602 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003603
3604 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003605 return Runtime::GetObjectProperty(args.at<Object>(0),
3606 args.at<Object>(1));
3607}
3608
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003609// Implements part of 8.12.9 DefineOwnProperty.
3610// There are 3 cases that lead here:
3611// Step 4b - define a new accessor property.
3612// Steps 9c & 12 - replace an existing data property with an accessor property.
3613// Step 12 - update an existing accessor property with an accessor or generic
3614// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003615static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003616 ASSERT(args.length() == 5);
3617 HandleScope scope;
3618 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3619 CONVERT_CHECKED(String, name, args[1]);
3620 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003621 Object* fun = args[3];
3622 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003623 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3624 int unchecked = flag_attr->value();
3625 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3626 RUNTIME_ASSERT(!obj->IsNull());
3627 LookupResult result;
3628 obj->LocalLookupRealNamedProperty(name, &result);
3629
3630 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3631 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3632 // delete it to avoid running into trouble in DefineAccessor, which
3633 // handles this incorrectly if the property is readonly (does nothing)
3634 if (result.IsProperty() &&
3635 (result.type() == FIELD || result.type() == NORMAL
3636 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003637 Object* ok;
3638 { MaybeObject* maybe_ok =
3639 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3640 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3641 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003642 }
3643 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3644}
3645
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003646// Implements part of 8.12.9 DefineOwnProperty.
3647// There are 3 cases that lead here:
3648// Step 4a - define a new data property.
3649// Steps 9b & 12 - replace an existing accessor property with a data property.
3650// Step 12 - update an existing data property with a data or generic
3651// descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003652static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003653 ASSERT(args.length() == 4);
3654 HandleScope scope;
3655 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3656 CONVERT_ARG_CHECKED(String, name, 1);
3657 Handle<Object> obj_value = args.at<Object>(2);
3658
3659 CONVERT_CHECKED(Smi, flag, args[3]);
3660 int unchecked = flag->value();
3661 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3662
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003663 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3664
3665 // Check if this is an element.
3666 uint32_t index;
3667 bool is_element = name->AsArrayIndex(&index);
3668
3669 // Special case for elements if any of the flags are true.
3670 // If elements are in fast case we always implicitly assume that:
3671 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3672 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3673 is_element) {
3674 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003675 if (js_object->IsJSGlobalProxy()) {
3676 Handle<Object> proto(js_object->GetPrototype());
3677 // If proxy is detached, ignore the assignment. Alternatively,
3678 // we could throw an exception.
3679 if (proto->IsNull()) return *obj_value;
3680 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003681 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003682 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003683 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003684 // Make sure that we never go back to fast case.
3685 dictionary->set_requires_slow_elements();
3686 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003687 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003688 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003689 }
3690
ager@chromium.org5c838252010-02-19 08:53:10 +00003691 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003692 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003693
ager@chromium.org5c838252010-02-19 08:53:10 +00003694 // Take special care when attributes are different and there is already
3695 // a property. For simplicity we normalize the property which enables us
3696 // to not worry about changing the instance_descriptor and creating a new
3697 // map. The current version of SetObjectProperty does not handle attributes
3698 // correctly in the case where a property is a field and is reset with
3699 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003700 if (result.IsProperty() &&
3701 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003702 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003703 if (js_object->IsJSGlobalProxy()) {
3704 // Since the result is a property, the prototype will exist so
3705 // we don't have to check for null.
3706 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003707 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003708 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003709 // Use IgnoreAttributes version since a readonly property may be
3710 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003711 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3712 *obj_value,
3713 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003714 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003715
ager@chromium.org5c838252010-02-19 08:53:10 +00003716 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3717}
3718
3719
lrn@chromium.org303ada72010-10-27 09:33:13 +00003720MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3721 Handle<Object> key,
3722 Handle<Object> value,
3723 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003724 HandleScope scope;
3725
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003727 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728 Handle<Object> error =
3729 Factory::NewTypeError("non_object_property_store",
3730 HandleVector(args, 2));
3731 return Top::Throw(*error);
3732 }
3733
3734 // If the object isn't a JavaScript object, we ignore the store.
3735 if (!object->IsJSObject()) return *value;
3736
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003737 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003739 // Check if the given key is an array index.
3740 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003741 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3743 // of a string using [] notation. We need to support this too in
3744 // JavaScript.
3745 // In the case of a String object we just need to redirect the assignment to
3746 // the underlying string if the index is in range. Since the underlying
3747 // string does nothing with the assignment then we can ignore such
3748 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003749 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003750 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003751 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003753 Handle<Object> result = SetElement(js_object, index, value);
3754 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003755 return *value;
3756 }
3757
3758 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003759 Handle<Object> result;
3760 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003761 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003763 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003764 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003765 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003767 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003768 return *value;
3769 }
3770
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772 bool has_pending_exception = false;
3773 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3774 if (has_pending_exception) return Failure::Exception();
3775 Handle<String> name = Handle<String>::cast(converted);
3776
3777 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003778 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003779 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003780 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781 }
3782}
3783
3784
lrn@chromium.org303ada72010-10-27 09:33:13 +00003785MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3786 Handle<Object> key,
3787 Handle<Object> value,
3788 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003789 HandleScope scope;
3790
3791 // Check if the given key is an array index.
3792 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003793 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003794 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3795 // of a string using [] notation. We need to support this too in
3796 // JavaScript.
3797 // In the case of a String object we just need to redirect the assignment to
3798 // the underlying string if the index is in range. Since the underlying
3799 // string does nothing with the assignment then we can ignore such
3800 // assignments.
3801 if (js_object->IsStringObjectWithCharacterAt(index)) {
3802 return *value;
3803 }
3804
3805 return js_object->SetElement(index, *value);
3806 }
3807
3808 if (key->IsString()) {
3809 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003810 return js_object->SetElement(index, *value);
3811 } else {
3812 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003813 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003814 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3815 *value,
3816 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003817 }
3818 }
3819
3820 // Call-back into JavaScript to convert the key to a string.
3821 bool has_pending_exception = false;
3822 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3823 if (has_pending_exception) return Failure::Exception();
3824 Handle<String> name = Handle<String>::cast(converted);
3825
3826 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003827 return js_object->SetElement(index, *value);
3828 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003829 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003830 }
3831}
3832
3833
lrn@chromium.org303ada72010-10-27 09:33:13 +00003834MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3835 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003836 HandleScope scope;
3837
3838 // Check if the given key is an array index.
3839 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003840 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003841 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3842 // characters of a string using [] notation. In the case of a
3843 // String object we just need to redirect the deletion to the
3844 // underlying string if the index is in range. Since the
3845 // underlying string does nothing with the deletion, we can ignore
3846 // such deletions.
3847 if (js_object->IsStringObjectWithCharacterAt(index)) {
3848 return Heap::true_value();
3849 }
3850
3851 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3852 }
3853
3854 Handle<String> key_string;
3855 if (key->IsString()) {
3856 key_string = Handle<String>::cast(key);
3857 } else {
3858 // Call-back into JavaScript to convert the key to a string.
3859 bool has_pending_exception = false;
3860 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3861 if (has_pending_exception) return Failure::Exception();
3862 key_string = Handle<String>::cast(converted);
3863 }
3864
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003865 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003866 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3867}
3868
3869
lrn@chromium.org303ada72010-10-27 09:33:13 +00003870static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003871 NoHandleAllocation ha;
3872 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3873
3874 Handle<Object> object = args.at<Object>(0);
3875 Handle<Object> key = args.at<Object>(1);
3876 Handle<Object> value = args.at<Object>(2);
3877
3878 // Compute attributes.
3879 PropertyAttributes attributes = NONE;
3880 if (args.length() == 4) {
3881 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003882 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003883 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003884 RUNTIME_ASSERT(
3885 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3886 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003887 }
3888 return Runtime::SetObjectProperty(object, key, value, attributes);
3889}
3890
3891
3892// Set a local property, even if it is READ_ONLY. If the property does not
3893// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003894static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003895 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003896 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003897 CONVERT_CHECKED(JSObject, object, args[0]);
3898 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003899 // Compute attributes.
3900 PropertyAttributes attributes = NONE;
3901 if (args.length() == 4) {
3902 CONVERT_CHECKED(Smi, value_obj, args[3]);
3903 int unchecked_value = value_obj->value();
3904 // Only attribute bits should be set.
3905 RUNTIME_ASSERT(
3906 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3907 attributes = static_cast<PropertyAttributes>(unchecked_value);
3908 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003909
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003910 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003911 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003912}
3913
3914
lrn@chromium.org303ada72010-10-27 09:33:13 +00003915static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916 NoHandleAllocation ha;
3917 ASSERT(args.length() == 2);
3918
3919 CONVERT_CHECKED(JSObject, object, args[0]);
3920 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003921 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003922}
3923
3924
ager@chromium.org9085a012009-05-11 19:22:57 +00003925static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3926 Handle<String> key) {
3927 if (object->HasLocalProperty(*key)) return Heap::true_value();
3928 // Handle hidden prototypes. If there's a hidden prototype above this thing
3929 // then we have to check it for properties, because they are supposed to
3930 // look like they are on this object.
3931 Handle<Object> proto(object->GetPrototype());
3932 if (proto->IsJSObject() &&
3933 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3934 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3935 }
3936 return Heap::false_value();
3937}
3938
3939
lrn@chromium.org303ada72010-10-27 09:33:13 +00003940static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003941 NoHandleAllocation ha;
3942 ASSERT(args.length() == 2);
3943 CONVERT_CHECKED(String, key, args[1]);
3944
ager@chromium.org9085a012009-05-11 19:22:57 +00003945 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003947 if (obj->IsJSObject()) {
3948 JSObject* object = JSObject::cast(obj);
3949 // Fast case - no interceptors.
3950 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3951 // Slow case. Either it's not there or we have an interceptor. We should
3952 // have handles for this kind of deal.
3953 HandleScope scope;
3954 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3955 Handle<String>(key));
3956 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957 // Well, there is one exception: Handle [] on strings.
3958 uint32_t index;
3959 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003960 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003961 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003962 return Heap::true_value();
3963 }
3964 }
3965 return Heap::false_value();
3966}
3967
3968
lrn@chromium.org303ada72010-10-27 09:33:13 +00003969static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 NoHandleAllocation na;
3971 ASSERT(args.length() == 2);
3972
3973 // Only JS objects can have properties.
3974 if (args[0]->IsJSObject()) {
3975 JSObject* object = JSObject::cast(args[0]);
3976 CONVERT_CHECKED(String, key, args[1]);
3977 if (object->HasProperty(key)) return Heap::true_value();
3978 }
3979 return Heap::false_value();
3980}
3981
3982
lrn@chromium.org303ada72010-10-27 09:33:13 +00003983static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 NoHandleAllocation na;
3985 ASSERT(args.length() == 2);
3986
3987 // Only JS objects can have elements.
3988 if (args[0]->IsJSObject()) {
3989 JSObject* object = JSObject::cast(args[0]);
3990 CONVERT_CHECKED(Smi, index_obj, args[1]);
3991 uint32_t index = index_obj->value();
3992 if (object->HasElement(index)) return Heap::true_value();
3993 }
3994 return Heap::false_value();
3995}
3996
3997
lrn@chromium.org303ada72010-10-27 09:33:13 +00003998static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999 NoHandleAllocation ha;
4000 ASSERT(args.length() == 2);
4001
4002 CONVERT_CHECKED(JSObject, object, args[0]);
4003 CONVERT_CHECKED(String, key, args[1]);
4004
4005 uint32_t index;
4006 if (key->AsArrayIndex(&index)) {
4007 return Heap::ToBoolean(object->HasElement(index));
4008 }
4009
ager@chromium.org870a0b62008-11-04 11:43:05 +00004010 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
4011 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004012}
4013
4014
lrn@chromium.org303ada72010-10-27 09:33:13 +00004015static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 HandleScope scope;
4017 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004018 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 return *GetKeysFor(object);
4020}
4021
4022
4023// Returns either a FixedArray as Runtime_GetPropertyNames,
4024// or, if the given object has an enum cache that contains
4025// all enumerable properties of the object and its prototypes
4026// have none, the map of the object. This is used to speed up
4027// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004028static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 ASSERT(args.length() == 1);
4030
4031 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4032
4033 if (raw_object->IsSimpleEnum()) return raw_object->map();
4034
4035 HandleScope scope;
4036 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004037 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4038 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039
4040 // Test again, since cache may have been built by preceding call.
4041 if (object->IsSimpleEnum()) return object->map();
4042
4043 return *content;
4044}
4045
4046
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004047// Find the length of the prototype chain that is to to handled as one. If a
4048// prototype object is hidden it is to be viewed as part of the the object it
4049// is prototype for.
4050static int LocalPrototypeChainLength(JSObject* obj) {
4051 int count = 1;
4052 Object* proto = obj->GetPrototype();
4053 while (proto->IsJSObject() &&
4054 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4055 count++;
4056 proto = JSObject::cast(proto)->GetPrototype();
4057 }
4058 return count;
4059}
4060
4061
4062// Return the names of the local named properties.
4063// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004064static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004065 HandleScope scope;
4066 ASSERT(args.length() == 1);
4067 if (!args[0]->IsJSObject()) {
4068 return Heap::undefined_value();
4069 }
4070 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4071
4072 // Skip the global proxy as it has no properties and always delegates to the
4073 // real global object.
4074 if (obj->IsJSGlobalProxy()) {
4075 // Only collect names if access is permitted.
4076 if (obj->IsAccessCheckNeeded() &&
4077 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
4078 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4079 return *Factory::NewJSArray(0);
4080 }
4081 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4082 }
4083
4084 // Find the number of objects making up this.
4085 int length = LocalPrototypeChainLength(*obj);
4086
4087 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004088 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004089 int total_property_count = 0;
4090 Handle<JSObject> jsproto = obj;
4091 for (int i = 0; i < length; i++) {
4092 // Only collect names if access is permitted.
4093 if (jsproto->IsAccessCheckNeeded() &&
4094 !Top::MayNamedAccess(*jsproto,
4095 Heap::undefined_value(),
4096 v8::ACCESS_KEYS)) {
4097 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4098 return *Factory::NewJSArray(0);
4099 }
4100 int n;
4101 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4102 local_property_count[i] = n;
4103 total_property_count += n;
4104 if (i < length - 1) {
4105 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4106 }
4107 }
4108
4109 // Allocate an array with storage for all the property names.
4110 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4111
4112 // Get the property names.
4113 jsproto = obj;
4114 int proto_with_hidden_properties = 0;
4115 for (int i = 0; i < length; i++) {
4116 jsproto->GetLocalPropertyNames(*names,
4117 i == 0 ? 0 : local_property_count[i - 1]);
4118 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4119 proto_with_hidden_properties++;
4120 }
4121 if (i < length - 1) {
4122 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4123 }
4124 }
4125
4126 // Filter out name of hidden propeties object.
4127 if (proto_with_hidden_properties > 0) {
4128 Handle<FixedArray> old_names = names;
4129 names = Factory::NewFixedArray(
4130 names->length() - proto_with_hidden_properties);
4131 int dest_pos = 0;
4132 for (int i = 0; i < total_property_count; i++) {
4133 Object* name = old_names->get(i);
4134 if (name == Heap::hidden_symbol()) {
4135 continue;
4136 }
4137 names->set(dest_pos++, name);
4138 }
4139 }
4140
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004141 return *Factory::NewJSArrayWithElements(names);
4142}
4143
4144
4145// Return the names of the local indexed properties.
4146// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004147static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004148 HandleScope scope;
4149 ASSERT(args.length() == 1);
4150 if (!args[0]->IsJSObject()) {
4151 return Heap::undefined_value();
4152 }
4153 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4154
4155 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4156 Handle<FixedArray> names = Factory::NewFixedArray(n);
4157 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4158 return *Factory::NewJSArrayWithElements(names);
4159}
4160
4161
4162// Return information on whether an object has a named or indexed interceptor.
4163// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004164static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004165 HandleScope scope;
4166 ASSERT(args.length() == 1);
4167 if (!args[0]->IsJSObject()) {
4168 return Smi::FromInt(0);
4169 }
4170 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4171
4172 int result = 0;
4173 if (obj->HasNamedInterceptor()) result |= 2;
4174 if (obj->HasIndexedInterceptor()) result |= 1;
4175
4176 return Smi::FromInt(result);
4177}
4178
4179
4180// Return property names from named interceptor.
4181// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004182static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004183 HandleScope scope;
4184 ASSERT(args.length() == 1);
4185 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4186
4187 if (obj->HasNamedInterceptor()) {
4188 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4189 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4190 }
4191 return Heap::undefined_value();
4192}
4193
4194
4195// Return element names from indexed interceptor.
4196// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004197static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004198 HandleScope scope;
4199 ASSERT(args.length() == 1);
4200 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4201
4202 if (obj->HasIndexedInterceptor()) {
4203 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4204 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4205 }
4206 return Heap::undefined_value();
4207}
4208
4209
lrn@chromium.org303ada72010-10-27 09:33:13 +00004210static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004211 ASSERT_EQ(args.length(), 1);
4212 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4213 HandleScope scope;
4214 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004215
4216 if (object->IsJSGlobalProxy()) {
4217 Handle<Object> proto(object->GetPrototype());
4218 // If proxy is detached we simply return an empty array.
4219 if (proto->IsNull()) return *Factory::NewJSArray(0);
4220 object = Handle<JSObject>::cast(proto);
4221 }
4222
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004223 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4224 LOCAL_ONLY);
4225 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4226 // property array and since the result is mutable we have to create
4227 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004228 int length = contents->length();
4229 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4230 for (int i = 0; i < length; i++) {
4231 Object* entry = contents->get(i);
4232 if (entry->IsString()) {
4233 copy->set(i, entry);
4234 } else {
4235 ASSERT(entry->IsNumber());
4236 HandleScope scope;
4237 Handle<Object> entry_handle(entry);
4238 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4239 copy->set(i, *entry_str);
4240 }
4241 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004242 return *Factory::NewJSArrayWithElements(copy);
4243}
4244
4245
lrn@chromium.org303ada72010-10-27 09:33:13 +00004246static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004247 NoHandleAllocation ha;
4248 ASSERT(args.length() == 1);
4249
4250 // Compute the frame holding the arguments.
4251 JavaScriptFrameIterator it;
4252 it.AdvanceToArgumentsFrame();
4253 JavaScriptFrame* frame = it.frame();
4254
4255 // Get the actual number of provided arguments.
4256 const uint32_t n = frame->GetProvidedParametersCount();
4257
4258 // Try to convert the key to an index. If successful and within
4259 // index return the the argument from the frame.
4260 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004261 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004262 return frame->GetParameter(index);
4263 }
4264
4265 // Convert the key to a string.
4266 HandleScope scope;
4267 bool exception = false;
4268 Handle<Object> converted =
4269 Execution::ToString(args.at<Object>(0), &exception);
4270 if (exception) return Failure::Exception();
4271 Handle<String> key = Handle<String>::cast(converted);
4272
4273 // Try to convert the string key into an array index.
4274 if (key->AsArrayIndex(&index)) {
4275 if (index < n) {
4276 return frame->GetParameter(index);
4277 } else {
4278 return Top::initial_object_prototype()->GetElement(index);
4279 }
4280 }
4281
4282 // Handle special arguments properties.
4283 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4284 if (key->Equals(Heap::callee_symbol())) return frame->function();
4285
4286 // Lookup in the initial Object.prototype object.
4287 return Top::initial_object_prototype()->GetProperty(*key);
4288}
4289
4290
lrn@chromium.org303ada72010-10-27 09:33:13 +00004291static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004292 HandleScope scope;
4293
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004294 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004295 Handle<Object> object = args.at<Object>(0);
4296 if (object->IsJSObject()) {
4297 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004298 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004299 MaybeObject* ok = js_object->TransformToFastProperties(0);
4300 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004301 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004302 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004303 return *object;
4304}
4305
4306
lrn@chromium.org303ada72010-10-27 09:33:13 +00004307static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004308 HandleScope scope;
4309
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004310 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004311 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004312 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004313 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004314 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004315 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004316 return *object;
4317}
4318
4319
lrn@chromium.org303ada72010-10-27 09:33:13 +00004320static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 NoHandleAllocation ha;
4322 ASSERT(args.length() == 1);
4323
4324 return args[0]->ToBoolean();
4325}
4326
4327
4328// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4329// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004330static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004331 NoHandleAllocation ha;
4332
4333 Object* obj = args[0];
4334 if (obj->IsNumber()) return Heap::number_symbol();
4335 HeapObject* heap_obj = HeapObject::cast(obj);
4336
4337 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004338 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004339
4340 InstanceType instance_type = heap_obj->map()->instance_type();
4341 if (instance_type < FIRST_NONSTRING_TYPE) {
4342 return Heap::string_symbol();
4343 }
4344
4345 switch (instance_type) {
4346 case ODDBALL_TYPE:
4347 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4348 return Heap::boolean_symbol();
4349 }
4350 if (heap_obj->IsNull()) {
4351 return Heap::object_symbol();
4352 }
4353 ASSERT(heap_obj->IsUndefined());
4354 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004355 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004356 return Heap::function_symbol();
4357 default:
4358 // For any kind of object not handled above, the spec rule for
4359 // host objects gives that it is okay to return "object"
4360 return Heap::object_symbol();
4361 }
4362}
4363
4364
lrn@chromium.org25156de2010-04-06 13:10:27 +00004365static bool AreDigits(const char*s, int from, int to) {
4366 for (int i = from; i < to; i++) {
4367 if (s[i] < '0' || s[i] > '9') return false;
4368 }
4369
4370 return true;
4371}
4372
4373
4374static int ParseDecimalInteger(const char*s, int from, int to) {
4375 ASSERT(to - from < 10); // Overflow is not possible.
4376 ASSERT(from < to);
4377 int d = s[from] - '0';
4378
4379 for (int i = from + 1; i < to; i++) {
4380 d = 10 * d + (s[i] - '0');
4381 }
4382
4383 return d;
4384}
4385
4386
lrn@chromium.org303ada72010-10-27 09:33:13 +00004387static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004388 NoHandleAllocation ha;
4389 ASSERT(args.length() == 1);
4390 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004391 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004392
4393 // Fast case: short integer or some sorts of junk values.
4394 int len = subject->length();
4395 if (subject->IsSeqAsciiString()) {
4396 if (len == 0) return Smi::FromInt(0);
4397
4398 char const* data = SeqAsciiString::cast(subject)->GetChars();
4399 bool minus = (data[0] == '-');
4400 int start_pos = (minus ? 1 : 0);
4401
4402 if (start_pos == len) {
4403 return Heap::nan_value();
4404 } else if (data[start_pos] > '9') {
4405 // Fast check for a junk value. A valid string may start from a
4406 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4407 // the 'I' character ('Infinity'). All of that have codes not greater than
4408 // '9' except 'I'.
4409 if (data[start_pos] != 'I') {
4410 return Heap::nan_value();
4411 }
4412 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4413 // The maximal/minimal smi has 10 digits. If the string has less digits we
4414 // know it will fit into the smi-data type.
4415 int d = ParseDecimalInteger(data, start_pos, len);
4416 if (minus) {
4417 if (d == 0) return Heap::minus_zero_value();
4418 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004419 } else if (!subject->HasHashCode() &&
4420 len <= String::kMaxArrayIndexSize &&
4421 (len == 1 || data[0] != '0')) {
4422 // String hash is not calculated yet but all the data are present.
4423 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004424 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004425#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004426 subject->Hash(); // Force hash calculation.
4427 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4428 static_cast<int>(hash));
4429#endif
4430 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004431 }
4432 return Smi::FromInt(d);
4433 }
4434 }
4435
4436 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004437 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4438}
4439
4440
lrn@chromium.org303ada72010-10-27 09:33:13 +00004441static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004442 NoHandleAllocation ha;
4443 ASSERT(args.length() == 1);
4444
4445 CONVERT_CHECKED(JSArray, codes, args[0]);
4446 int length = Smi::cast(codes->length())->value();
4447
4448 // Check if the string can be ASCII.
4449 int i;
4450 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004451 Object* element;
4452 { MaybeObject* maybe_element = codes->GetElement(i);
4453 // We probably can't get an exception here, but just in order to enforce
4454 // the checking of inputs in the runtime calls we check here.
4455 if (!maybe_element->ToObject(&element)) return maybe_element;
4456 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004457 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4458 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4459 break;
4460 }
4461
lrn@chromium.org303ada72010-10-27 09:33:13 +00004462 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004464 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004466 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 }
4468
lrn@chromium.org303ada72010-10-27 09:33:13 +00004469 Object* object = NULL;
4470 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 String* result = String::cast(object);
4472 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004473 Object* element;
4474 { MaybeObject* maybe_element = codes->GetElement(i);
4475 if (!maybe_element->ToObject(&element)) return maybe_element;
4476 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004478 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479 }
4480 return result;
4481}
4482
4483
4484// kNotEscaped is generated by the following:
4485//
4486// #!/bin/perl
4487// for (my $i = 0; $i < 256; $i++) {
4488// print "\n" if $i % 16 == 0;
4489// my $c = chr($i);
4490// my $escaped = 1;
4491// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4492// print $escaped ? "0, " : "1, ";
4493// }
4494
4495
4496static bool IsNotEscaped(uint16_t character) {
4497 // Only for 8 bit characters, the rest are always escaped (in a different way)
4498 ASSERT(character < 256);
4499 static const char kNotEscaped[256] = {
4500 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4501 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4502 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4503 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4504 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4505 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4506 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4507 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4508 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4509 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4510 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4514 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4515 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4516 };
4517 return kNotEscaped[character] != 0;
4518}
4519
4520
lrn@chromium.org303ada72010-10-27 09:33:13 +00004521static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004522 const char hex_chars[] = "0123456789ABCDEF";
4523 NoHandleAllocation ha;
4524 ASSERT(args.length() == 1);
4525 CONVERT_CHECKED(String, source, args[0]);
4526
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004527 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004528
4529 int escaped_length = 0;
4530 int length = source->length();
4531 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004532 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 buffer->Reset(source);
4534 while (buffer->has_more()) {
4535 uint16_t character = buffer->GetNext();
4536 if (character >= 256) {
4537 escaped_length += 6;
4538 } else if (IsNotEscaped(character)) {
4539 escaped_length++;
4540 } else {
4541 escaped_length += 3;
4542 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004543 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004544 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004545 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004546 Top::context()->mark_out_of_memory();
4547 return Failure::OutOfMemoryException();
4548 }
4549 }
4550 }
4551 // No length change implies no change. Return original string if no change.
4552 if (escaped_length == length) {
4553 return source;
4554 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004555 Object* o;
4556 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4557 if (!maybe_o->ToObject(&o)) return maybe_o;
4558 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004559 String* destination = String::cast(o);
4560 int dest_position = 0;
4561
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004562 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004563 buffer->Rewind();
4564 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004565 uint16_t chr = buffer->GetNext();
4566 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004567 destination->Set(dest_position, '%');
4568 destination->Set(dest_position+1, 'u');
4569 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4570 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4571 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4572 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004573 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004574 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004575 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004576 dest_position++;
4577 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004578 destination->Set(dest_position, '%');
4579 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4580 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004581 dest_position += 3;
4582 }
4583 }
4584 return destination;
4585}
4586
4587
4588static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4589 static const signed char kHexValue['g'] = {
4590 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4591 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4592 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4593 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4594 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4595 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4596 -1, 10, 11, 12, 13, 14, 15 };
4597
4598 if (character1 > 'f') return -1;
4599 int hi = kHexValue[character1];
4600 if (hi == -1) return -1;
4601 if (character2 > 'f') return -1;
4602 int lo = kHexValue[character2];
4603 if (lo == -1) return -1;
4604 return (hi << 4) + lo;
4605}
4606
4607
ager@chromium.org870a0b62008-11-04 11:43:05 +00004608static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004609 int i,
4610 int length,
4611 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004612 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004613 int32_t hi = 0;
4614 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004615 if (character == '%' &&
4616 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004617 source->Get(i + 1) == 'u' &&
4618 (hi = TwoDigitHex(source->Get(i + 2),
4619 source->Get(i + 3))) != -1 &&
4620 (lo = TwoDigitHex(source->Get(i + 4),
4621 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004622 *step = 6;
4623 return (hi << 8) + lo;
4624 } else if (character == '%' &&
4625 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004626 (lo = TwoDigitHex(source->Get(i + 1),
4627 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628 *step = 3;
4629 return lo;
4630 } else {
4631 *step = 1;
4632 return character;
4633 }
4634}
4635
4636
lrn@chromium.org303ada72010-10-27 09:33:13 +00004637static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004638 NoHandleAllocation ha;
4639 ASSERT(args.length() == 1);
4640 CONVERT_CHECKED(String, source, args[0]);
4641
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004642 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004643
4644 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004645 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004646
4647 int unescaped_length = 0;
4648 for (int i = 0; i < length; unescaped_length++) {
4649 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004650 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004651 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004653 i += step;
4654 }
4655
4656 // No length change implies no change. Return original string if no change.
4657 if (unescaped_length == length)
4658 return source;
4659
lrn@chromium.org303ada72010-10-27 09:33:13 +00004660 Object* o;
4661 { MaybeObject* maybe_o = ascii ?
4662 Heap::AllocateRawAsciiString(unescaped_length) :
4663 Heap::AllocateRawTwoByteString(unescaped_length);
4664 if (!maybe_o->ToObject(&o)) return maybe_o;
4665 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004666 String* destination = String::cast(o);
4667
4668 int dest_position = 0;
4669 for (int i = 0; i < length; dest_position++) {
4670 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004671 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672 i += step;
4673 }
4674 return destination;
4675}
4676
4677
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004678static const unsigned int kQuoteTableLength = 128u;
4679
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004680static const int kJsonQuotesCharactersPerEntry = 8;
4681static const char* const JsonQuotes =
4682 "\\u0000 \\u0001 \\u0002 \\u0003 "
4683 "\\u0004 \\u0005 \\u0006 \\u0007 "
4684 "\\b \\t \\n \\u000b "
4685 "\\f \\r \\u000e \\u000f "
4686 "\\u0010 \\u0011 \\u0012 \\u0013 "
4687 "\\u0014 \\u0015 \\u0016 \\u0017 "
4688 "\\u0018 \\u0019 \\u001a \\u001b "
4689 "\\u001c \\u001d \\u001e \\u001f "
4690 " ! \\\" # "
4691 "$ % & ' "
4692 "( ) * + "
4693 ", - . / "
4694 "0 1 2 3 "
4695 "4 5 6 7 "
4696 "8 9 : ; "
4697 "< = > ? "
4698 "@ A B C "
4699 "D E F G "
4700 "H I J K "
4701 "L M N O "
4702 "P Q R S "
4703 "T U V W "
4704 "X Y Z [ "
4705 "\\\\ ] ^ _ "
4706 "` a b c "
4707 "d e f g "
4708 "h i j k "
4709 "l m n o "
4710 "p q r s "
4711 "t u v w "
4712 "x y z { "
4713 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004714
4715
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004716// For a string that is less than 32k characters it should always be
4717// possible to allocate it in new space.
4718static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4719
4720
4721// Doing JSON quoting cannot make the string more than this many times larger.
4722static const int kJsonQuoteWorstCaseBlowup = 6;
4723
4724
4725// Covers the entire ASCII range (all other characters are unchanged by JSON
4726// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004727static const byte JsonQuoteLengths[kQuoteTableLength] = {
4728 6, 6, 6, 6, 6, 6, 6, 6,
4729 2, 2, 2, 6, 2, 2, 6, 6,
4730 6, 6, 6, 6, 6, 6, 6, 6,
4731 6, 6, 6, 6, 6, 6, 6, 6,
4732 1, 1, 2, 1, 1, 1, 1, 1,
4733 1, 1, 1, 1, 1, 1, 1, 1,
4734 1, 1, 1, 1, 1, 1, 1, 1,
4735 1, 1, 1, 1, 1, 1, 1, 1,
4736 1, 1, 1, 1, 1, 1, 1, 1,
4737 1, 1, 1, 1, 1, 1, 1, 1,
4738 1, 1, 1, 1, 1, 1, 1, 1,
4739 1, 1, 1, 1, 2, 1, 1, 1,
4740 1, 1, 1, 1, 1, 1, 1, 1,
4741 1, 1, 1, 1, 1, 1, 1, 1,
4742 1, 1, 1, 1, 1, 1, 1, 1,
4743 1, 1, 1, 1, 1, 1, 1, 1,
4744};
4745
4746
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004747template <typename StringType>
4748MaybeObject* AllocateRawString(int length);
4749
4750
4751template <>
4752MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4753 return Heap::AllocateRawTwoByteString(length);
4754}
4755
4756
4757template <>
4758MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4759 return Heap::AllocateRawAsciiString(length);
4760}
4761
4762
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004763template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004764static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004765 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004766 const Char* read_cursor = characters.start();
4767 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004768 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004769 int quoted_length = kSpaceForQuotes;
4770 while (read_cursor < end) {
4771 Char c = *(read_cursor++);
4772 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4773 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004774 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004775 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004776 }
4777 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004778 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4779 Object* new_object;
4780 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004781 return new_alloc;
4782 }
4783 StringType* new_string = StringType::cast(new_object);
4784
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004785 Char* write_cursor = reinterpret_cast<Char*>(
4786 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004787 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004788 *(write_cursor++) = '"';
4789
4790 read_cursor = characters.start();
4791 while (read_cursor < end) {
4792 Char c = *(read_cursor++);
4793 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4794 *(write_cursor++) = c;
4795 } else {
4796 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4797 const char* replacement = JsonQuotes +
4798 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4799 for (int i = 0; i < len; i++) {
4800 *write_cursor++ = *replacement++;
4801 }
4802 }
4803 }
4804 *(write_cursor++) = '"';
4805 return new_string;
4806}
4807
4808
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004809template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004810static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4811 int length = characters.length();
4812 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004813 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004814 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4815 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004816 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004817 }
4818
4819 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4820 Object* new_object;
4821 if (!new_alloc->ToObject(&new_object)) {
4822 return new_alloc;
4823 }
4824 if (!Heap::new_space()->Contains(new_object)) {
4825 // Even if our string is small enough to fit in new space we still have to
4826 // handle it being allocated in old space as may happen in the third
4827 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4828 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004829 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004830 }
4831 StringType* new_string = StringType::cast(new_object);
4832 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004833
4834 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4835 Char* write_cursor = reinterpret_cast<Char*>(
4836 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004837 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004838 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004839
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004840 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004841 const Char* end = read_cursor + length;
4842 while (read_cursor < end) {
4843 Char c = *(read_cursor++);
4844 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4845 *(write_cursor++) = c;
4846 } else {
4847 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4848 const char* replacement = JsonQuotes +
4849 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4850 write_cursor[0] = replacement[0];
4851 if (len > 1) {
4852 write_cursor[1] = replacement[1];
4853 if (len > 2) {
4854 ASSERT(len == 6);
4855 write_cursor[2] = replacement[2];
4856 write_cursor[3] = replacement[3];
4857 write_cursor[4] = replacement[4];
4858 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004859 }
4860 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004861 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004862 }
4863 }
4864 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004865
4866 int final_length = static_cast<int>(
4867 write_cursor - reinterpret_cast<Char*>(
4868 new_string->address() + SeqAsciiString::kHeaderSize));
4869 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4870 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004871 return new_string;
4872}
4873
4874
4875static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4876 NoHandleAllocation ha;
4877 CONVERT_CHECKED(String, str, args[0]);
4878 if (!str->IsFlat()) {
4879 MaybeObject* try_flatten = str->TryFlatten();
4880 Object* flat;
4881 if (!try_flatten->ToObject(&flat)) {
4882 return try_flatten;
4883 }
4884 str = String::cast(flat);
4885 ASSERT(str->IsFlat());
4886 }
4887 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004888 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004889 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004890 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004891 }
4892}
4893
4894
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004895static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4896 NoHandleAllocation ha;
4897 CONVERT_CHECKED(String, str, args[0]);
4898 if (!str->IsFlat()) {
4899 MaybeObject* try_flatten = str->TryFlatten();
4900 Object* flat;
4901 if (!try_flatten->ToObject(&flat)) {
4902 return try_flatten;
4903 }
4904 str = String::cast(flat);
4905 ASSERT(str->IsFlat());
4906 }
4907 if (str->IsTwoByteRepresentation()) {
4908 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
4909 } else {
4910 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
4911 }
4912}
4913
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004914
lrn@chromium.org303ada72010-10-27 09:33:13 +00004915static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916 NoHandleAllocation ha;
4917
4918 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004919 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004920
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004921 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004922
lrn@chromium.org25156de2010-04-06 13:10:27 +00004923 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4924 double value = StringToInt(s, radix);
4925 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004926}
4927
4928
lrn@chromium.org303ada72010-10-27 09:33:13 +00004929static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004930 NoHandleAllocation ha;
4931 CONVERT_CHECKED(String, str, args[0]);
4932
4933 // ECMA-262 section 15.1.2.3, empty string is NaN
4934 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4935
4936 // Create a number object from the value.
4937 return Heap::NumberFromDouble(value);
4938}
4939
4940
4941static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4942static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4943
4944
4945template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004946MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4947 String* s,
4948 int length,
4949 int input_string_length,
4950 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004951 // We try this twice, once with the assumption that the result is no longer
4952 // than the input and, if that assumption breaks, again with the exact
4953 // length. This may not be pretty, but it is nicer than what was here before
4954 // and I hereby claim my vaffel-is.
4955 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004956 // Allocate the resulting string.
4957 //
4958 // NOTE: This assumes that the upper/lower case of an ascii
4959 // character is also ascii. This is currently the case, but it
4960 // might break in the future if we implement more context and locale
4961 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004962 Object* o;
4963 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4964 ? Heap::AllocateRawAsciiString(length)
4965 : Heap::AllocateRawTwoByteString(length);
4966 if (!maybe_o->ToObject(&o)) return maybe_o;
4967 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004968 String* result = String::cast(o);
4969 bool has_changed_character = false;
4970
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004971 // Convert all characters to upper case, assuming that they will fit
4972 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004973 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004974 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004975 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004976 // We can assume that the string is not empty
4977 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004978 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004979 bool has_next = buffer->has_more();
4980 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004981 int char_length = mapping->get(current, next, chars);
4982 if (char_length == 0) {
4983 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004984 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985 i++;
4986 } else if (char_length == 1) {
4987 // Common case: converting the letter resulted in one character.
4988 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004989 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 has_changed_character = true;
4991 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004992 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004993 // We've assumed that the result would be as long as the
4994 // input but here is a character that converts to several
4995 // characters. No matter, we calculate the exact length
4996 // of the result and try the whole thing again.
4997 //
4998 // Note that this leaves room for optimization. We could just
4999 // memcpy what we already have to the result string. Also,
5000 // the result string is the last object allocated we could
5001 // "realloc" it and probably, in the vast majority of cases,
5002 // extend the existing string to be able to hold the full
5003 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005004 int next_length = 0;
5005 if (has_next) {
5006 next_length = mapping->get(next, 0, chars);
5007 if (next_length == 0) next_length = 1;
5008 }
5009 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005010 while (buffer->has_more()) {
5011 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005012 // NOTE: we use 0 as the next character here because, while
5013 // the next character may affect what a character converts to,
5014 // it does not in any case affect the length of what it convert
5015 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005016 int char_length = mapping->get(current, 0, chars);
5017 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005018 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005019 if (current_length > Smi::kMaxValue) {
5020 Top::context()->mark_out_of_memory();
5021 return Failure::OutOfMemoryException();
5022 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005023 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005024 // Try again with the real length.
5025 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005026 } else {
5027 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005028 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005029 i++;
5030 }
5031 has_changed_character = true;
5032 }
5033 current = next;
5034 }
5035 if (has_changed_character) {
5036 return result;
5037 } else {
5038 // If we didn't actually change anything in doing the conversion
5039 // we simple return the result and let the converted string
5040 // become garbage; there is no reason to keep two identical strings
5041 // alive.
5042 return s;
5043 }
5044}
5045
5046
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005047namespace {
5048
lrn@chromium.org303ada72010-10-27 09:33:13 +00005049static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5050
5051
5052// Given a word and two range boundaries returns a word with high bit
5053// set in every byte iff the corresponding input byte was strictly in
5054// the range (m, n). All the other bits in the result are cleared.
5055// This function is only useful when it can be inlined and the
5056// boundaries are statically known.
5057// Requires: all bytes in the input word and the boundaries must be
5058// ascii (less than 0x7F).
5059static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5060 // Every byte in an ascii string is less than or equal to 0x7F.
5061 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5062 // Use strict inequalities since in edge cases the function could be
5063 // further simplified.
5064 ASSERT(0 < m && m < n && n < 0x7F);
5065 // Has high bit set in every w byte less than n.
5066 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5067 // Has high bit set in every w byte greater than m.
5068 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5069 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5070}
5071
5072
5073enum AsciiCaseConversion {
5074 ASCII_TO_LOWER,
5075 ASCII_TO_UPPER
5076};
5077
5078
5079template <AsciiCaseConversion dir>
5080struct FastAsciiConverter {
5081 static bool Convert(char* dst, char* src, int length) {
5082#ifdef DEBUG
5083 char* saved_dst = dst;
5084 char* saved_src = src;
5085#endif
5086 // We rely on the distance between upper and lower case letters
5087 // being a known power of 2.
5088 ASSERT('a' - 'A' == (1 << 5));
5089 // Boundaries for the range of input characters than require conversion.
5090 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5091 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5092 bool changed = false;
5093 char* const limit = src + length;
5094#ifdef V8_HOST_CAN_READ_UNALIGNED
5095 // Process the prefix of the input that requires no conversion one
5096 // (machine) word at a time.
5097 while (src <= limit - sizeof(uintptr_t)) {
5098 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5099 if (AsciiRangeMask(w, lo, hi) != 0) {
5100 changed = true;
5101 break;
5102 }
5103 *reinterpret_cast<uintptr_t*>(dst) = w;
5104 src += sizeof(uintptr_t);
5105 dst += sizeof(uintptr_t);
5106 }
5107 // Process the remainder of the input performing conversion when
5108 // required one word at a time.
5109 while (src <= limit - sizeof(uintptr_t)) {
5110 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5111 uintptr_t m = AsciiRangeMask(w, lo, hi);
5112 // The mask has high (7th) bit set in every byte that needs
5113 // conversion and we know that the distance between cases is
5114 // 1 << 5.
5115 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5116 src += sizeof(uintptr_t);
5117 dst += sizeof(uintptr_t);
5118 }
5119#endif
5120 // Process the last few bytes of the input (or the whole input if
5121 // unaligned access is not supported).
5122 while (src < limit) {
5123 char c = *src;
5124 if (lo < c && c < hi) {
5125 c ^= (1 << 5);
5126 changed = true;
5127 }
5128 *dst = c;
5129 ++src;
5130 ++dst;
5131 }
5132#ifdef DEBUG
5133 CheckConvert(saved_dst, saved_src, length, changed);
5134#endif
5135 return changed;
5136 }
5137
5138#ifdef DEBUG
5139 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5140 bool expected_changed = false;
5141 for (int i = 0; i < length; i++) {
5142 if (dst[i] == src[i]) continue;
5143 expected_changed = true;
5144 if (dir == ASCII_TO_LOWER) {
5145 ASSERT('A' <= src[i] && src[i] <= 'Z');
5146 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5147 } else {
5148 ASSERT(dir == ASCII_TO_UPPER);
5149 ASSERT('a' <= src[i] && src[i] <= 'z');
5150 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5151 }
5152 }
5153 ASSERT(expected_changed == changed);
5154 }
5155#endif
5156};
5157
5158
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005159struct ToLowerTraits {
5160 typedef unibrow::ToLowercase UnibrowConverter;
5161
lrn@chromium.org303ada72010-10-27 09:33:13 +00005162 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005163};
5164
5165
5166struct ToUpperTraits {
5167 typedef unibrow::ToUppercase UnibrowConverter;
5168
lrn@chromium.org303ada72010-10-27 09:33:13 +00005169 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005170};
5171
5172} // namespace
5173
5174
5175template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005176MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005177 Arguments args,
5178 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005179 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005180 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005181 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005182
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005183 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005184 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005185 if (length == 0) return s;
5186
5187 // Simpler handling of ascii strings.
5188 //
5189 // NOTE: This assumes that the upper/lower case of an ascii
5190 // character is also ascii. This is currently the case, but it
5191 // might break in the future if we implement more context and locale
5192 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005193 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005194 Object* o;
5195 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5196 if (!maybe_o->ToObject(&o)) return maybe_o;
5197 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005198 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005199 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005200 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005201 return has_changed_character ? result : s;
5202 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005203
lrn@chromium.org303ada72010-10-27 09:33:13 +00005204 Object* answer;
5205 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5206 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5207 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005208 if (answer->IsSmi()) {
5209 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005210 { MaybeObject* maybe_answer =
5211 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5212 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5213 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005214 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005215 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005216}
5217
5218
lrn@chromium.org303ada72010-10-27 09:33:13 +00005219static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005220 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005221}
5222
5223
lrn@chromium.org303ada72010-10-27 09:33:13 +00005224static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005225 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226}
5227
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005228
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005229static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5230 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5231}
5232
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005233
lrn@chromium.org303ada72010-10-27 09:33:13 +00005234static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005235 NoHandleAllocation ha;
5236 ASSERT(args.length() == 3);
5237
5238 CONVERT_CHECKED(String, s, args[0]);
5239 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5240 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5241
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005242 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005243 int length = s->length();
5244
5245 int left = 0;
5246 if (trimLeft) {
5247 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5248 left++;
5249 }
5250 }
5251
5252 int right = length;
5253 if (trimRight) {
5254 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5255 right--;
5256 }
5257 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005258 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005259}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005260
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005261
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005262template <typename SubjectChar, typename PatternChar>
5263void FindStringIndices(Vector<const SubjectChar> subject,
5264 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005265 ZoneList<int>* indices,
5266 unsigned int limit) {
5267 ASSERT(limit > 0);
5268 // Collect indices of pattern in subject, and the end-of-string index.
5269 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005270 StringSearch<PatternChar, SubjectChar> search(pattern);
5271 int pattern_length = pattern.length();
5272 int index = 0;
5273 while (limit > 0) {
5274 index = search.Search(subject, index);
5275 if (index < 0) return;
5276 indices->Add(index);
5277 index += pattern_length;
5278 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005279 }
5280}
5281
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005282
lrn@chromium.org303ada72010-10-27 09:33:13 +00005283static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005284 ASSERT(args.length() == 3);
5285 HandleScope handle_scope;
5286 CONVERT_ARG_CHECKED(String, subject, 0);
5287 CONVERT_ARG_CHECKED(String, pattern, 1);
5288 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5289
5290 int subject_length = subject->length();
5291 int pattern_length = pattern->length();
5292 RUNTIME_ASSERT(pattern_length > 0);
5293
5294 // The limit can be very large (0xffffffffu), but since the pattern
5295 // isn't empty, we can never create more parts than ~half the length
5296 // of the subject.
5297
5298 if (!subject->IsFlat()) FlattenString(subject);
5299
5300 static const int kMaxInitialListCapacity = 16;
5301
5302 ZoneScope scope(DELETE_ON_EXIT);
5303
5304 // Find (up to limit) indices of separator and end-of-string in subject
5305 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5306 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005307 if (!pattern->IsFlat()) FlattenString(pattern);
5308
5309 // No allocation block.
5310 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005311 AssertNoAllocation nogc;
5312 if (subject->IsAsciiRepresentation()) {
5313 Vector<const char> subject_vector = subject->ToAsciiVector();
5314 if (pattern->IsAsciiRepresentation()) {
5315 FindStringIndices(subject_vector,
5316 pattern->ToAsciiVector(),
5317 &indices,
5318 limit);
5319 } else {
5320 FindStringIndices(subject_vector,
5321 pattern->ToUC16Vector(),
5322 &indices,
5323 limit);
5324 }
5325 } else {
5326 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5327 if (pattern->IsAsciiRepresentation()) {
5328 FindStringIndices(subject_vector,
5329 pattern->ToAsciiVector(),
5330 &indices,
5331 limit);
5332 } else {
5333 FindStringIndices(subject_vector,
5334 pattern->ToUC16Vector(),
5335 &indices,
5336 limit);
5337 }
5338 }
5339 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005340
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005341 if (static_cast<uint32_t>(indices.length()) < limit) {
5342 indices.Add(subject_length);
5343 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005344
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005345 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005346
5347 // Create JSArray of substrings separated by separator.
5348 int part_count = indices.length();
5349
5350 Handle<JSArray> result = Factory::NewJSArray(part_count);
5351 result->set_length(Smi::FromInt(part_count));
5352
5353 ASSERT(result->HasFastElements());
5354
5355 if (part_count == 1 && indices.at(0) == subject_length) {
5356 FixedArray::cast(result->elements())->set(0, *subject);
5357 return *result;
5358 }
5359
5360 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5361 int part_start = 0;
5362 for (int i = 0; i < part_count; i++) {
5363 HandleScope local_loop_handle;
5364 int part_end = indices.at(i);
5365 Handle<String> substring =
5366 Factory::NewSubString(subject, part_start, part_end);
5367 elements->set(i, *substring);
5368 part_start = part_end + pattern_length;
5369 }
5370
5371 return *result;
5372}
5373
5374
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005375// Copies ascii characters to the given fixed array looking up
5376// one-char strings in the cache. Gives up on the first char that is
5377// not in the cache and fills the remainder with smi zeros. Returns
5378// the length of the successfully copied prefix.
5379static int CopyCachedAsciiCharsToArray(const char* chars,
5380 FixedArray* elements,
5381 int length) {
5382 AssertNoAllocation nogc;
5383 FixedArray* ascii_cache = Heap::single_character_string_cache();
5384 Object* undefined = Heap::undefined_value();
5385 int i;
5386 for (i = 0; i < length; ++i) {
5387 Object* value = ascii_cache->get(chars[i]);
5388 if (value == undefined) break;
5389 ASSERT(!Heap::InNewSpace(value));
5390 elements->set(i, value, SKIP_WRITE_BARRIER);
5391 }
5392 if (i < length) {
5393 ASSERT(Smi::FromInt(0) == 0);
5394 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5395 }
5396#ifdef DEBUG
5397 for (int j = 0; j < length; ++j) {
5398 Object* element = elements->get(j);
5399 ASSERT(element == Smi::FromInt(0) ||
5400 (element->IsString() && String::cast(element)->LooksValid()));
5401 }
5402#endif
5403 return i;
5404}
5405
5406
5407// Converts a String to JSArray.
5408// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005409static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005410 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005411 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005412 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005413 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005414
5415 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005416 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005417
5418 Handle<FixedArray> elements;
5419 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005420 Object* obj;
5421 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5422 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5423 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005424 elements = Handle<FixedArray>(FixedArray::cast(obj));
5425
5426 Vector<const char> chars = s->ToAsciiVector();
5427 // Note, this will initialize all elements (not only the prefix)
5428 // to prevent GC from seeing partially initialized array.
5429 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5430 *elements,
5431 length);
5432
5433 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005434 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5435 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005436 }
5437 } else {
5438 elements = Factory::NewFixedArray(length);
5439 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005440 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5441 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005442 }
5443 }
5444
5445#ifdef DEBUG
5446 for (int i = 0; i < length; ++i) {
5447 ASSERT(String::cast(elements->get(i))->length() == 1);
5448 }
5449#endif
5450
5451 return *Factory::NewJSArrayWithElements(elements);
5452}
5453
5454
lrn@chromium.org303ada72010-10-27 09:33:13 +00005455static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005456 NoHandleAllocation ha;
5457 ASSERT(args.length() == 1);
5458 CONVERT_CHECKED(String, value, args[0]);
5459 return value->ToObject();
5460}
5461
5462
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005463bool Runtime::IsUpperCaseChar(uint16_t ch) {
5464 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5465 int char_length = to_upper_mapping.get(ch, 0, chars);
5466 return char_length == 0;
5467}
5468
5469
lrn@chromium.org303ada72010-10-27 09:33:13 +00005470static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005471 NoHandleAllocation ha;
5472 ASSERT(args.length() == 1);
5473
5474 Object* number = args[0];
5475 RUNTIME_ASSERT(number->IsNumber());
5476
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005477 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005478}
5479
5480
lrn@chromium.org303ada72010-10-27 09:33:13 +00005481static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005482 NoHandleAllocation ha;
5483 ASSERT(args.length() == 1);
5484
5485 Object* number = args[0];
5486 RUNTIME_ASSERT(number->IsNumber());
5487
5488 return Heap::NumberToString(number, false);
5489}
5490
5491
lrn@chromium.org303ada72010-10-27 09:33:13 +00005492static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005493 NoHandleAllocation ha;
5494 ASSERT(args.length() == 1);
5495
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005496 CONVERT_DOUBLE_CHECKED(number, args[0]);
5497
5498 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5499 if (number > 0 && number <= Smi::kMaxValue) {
5500 return Smi::FromInt(static_cast<int>(number));
5501 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502 return Heap::NumberFromDouble(DoubleToInteger(number));
5503}
5504
5505
lrn@chromium.org303ada72010-10-27 09:33:13 +00005506static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005507 NoHandleAllocation ha;
5508 ASSERT(args.length() == 1);
5509
5510 CONVERT_DOUBLE_CHECKED(number, args[0]);
5511
5512 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5513 if (number > 0 && number <= Smi::kMaxValue) {
5514 return Smi::FromInt(static_cast<int>(number));
5515 }
5516
5517 double double_value = DoubleToInteger(number);
5518 // Map both -0 and +0 to +0.
5519 if (double_value == 0) double_value = 0;
5520
5521 return Heap::NumberFromDouble(double_value);
5522}
5523
5524
lrn@chromium.org303ada72010-10-27 09:33:13 +00005525static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005526 NoHandleAllocation ha;
5527 ASSERT(args.length() == 1);
5528
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005529 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005530 return Heap::NumberFromUint32(number);
5531}
5532
5533
lrn@chromium.org303ada72010-10-27 09:33:13 +00005534static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005535 NoHandleAllocation ha;
5536 ASSERT(args.length() == 1);
5537
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005538 CONVERT_DOUBLE_CHECKED(number, args[0]);
5539
5540 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5541 if (number > 0 && number <= Smi::kMaxValue) {
5542 return Smi::FromInt(static_cast<int>(number));
5543 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005544 return Heap::NumberFromInt32(DoubleToInt32(number));
5545}
5546
5547
ager@chromium.org870a0b62008-11-04 11:43:05 +00005548// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5549// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005550static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005551 NoHandleAllocation ha;
5552 ASSERT(args.length() == 1);
5553
5554 Object* obj = args[0];
5555 if (obj->IsSmi()) {
5556 return obj;
5557 }
5558 if (obj->IsHeapNumber()) {
5559 double value = HeapNumber::cast(obj)->value();
5560 int int_value = FastD2I(value);
5561 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5562 return Smi::FromInt(int_value);
5563 }
5564 }
5565 return Heap::nan_value();
5566}
5567
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005568
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005569static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5570 NoHandleAllocation ha;
5571 ASSERT(args.length() == 0);
5572 return Heap::AllocateHeapNumber(0);
5573}
5574
5575
lrn@chromium.org303ada72010-10-27 09:33:13 +00005576static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577 NoHandleAllocation ha;
5578 ASSERT(args.length() == 2);
5579
5580 CONVERT_DOUBLE_CHECKED(x, args[0]);
5581 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005582 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583}
5584
5585
lrn@chromium.org303ada72010-10-27 09:33:13 +00005586static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587 NoHandleAllocation ha;
5588 ASSERT(args.length() == 2);
5589
5590 CONVERT_DOUBLE_CHECKED(x, args[0]);
5591 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005592 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005593}
5594
5595
lrn@chromium.org303ada72010-10-27 09:33:13 +00005596static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005597 NoHandleAllocation ha;
5598 ASSERT(args.length() == 2);
5599
5600 CONVERT_DOUBLE_CHECKED(x, args[0]);
5601 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005602 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603}
5604
5605
lrn@chromium.org303ada72010-10-27 09:33:13 +00005606static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 NoHandleAllocation ha;
5608 ASSERT(args.length() == 1);
5609
5610 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005611 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005612}
5613
5614
lrn@chromium.org303ada72010-10-27 09:33:13 +00005615static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005616 NoHandleAllocation ha;
5617 ASSERT(args.length() == 0);
5618
5619 return Heap::NumberFromDouble(9876543210.0);
5620}
5621
5622
lrn@chromium.org303ada72010-10-27 09:33:13 +00005623static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005624 NoHandleAllocation ha;
5625 ASSERT(args.length() == 2);
5626
5627 CONVERT_DOUBLE_CHECKED(x, args[0]);
5628 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005629 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005630}
5631
5632
lrn@chromium.org303ada72010-10-27 09:33:13 +00005633static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005634 NoHandleAllocation ha;
5635 ASSERT(args.length() == 2);
5636
5637 CONVERT_DOUBLE_CHECKED(x, args[0]);
5638 CONVERT_DOUBLE_CHECKED(y, args[1]);
5639
ager@chromium.org3811b432009-10-28 14:53:37 +00005640 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005641 // NumberFromDouble may return a Smi instead of a Number object
5642 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005643}
5644
5645
lrn@chromium.org303ada72010-10-27 09:33:13 +00005646static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005647 NoHandleAllocation ha;
5648 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005649 CONVERT_CHECKED(String, str1, args[0]);
5650 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005651 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005652 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005653}
5654
5655
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005656template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005657static inline void StringBuilderConcatHelper(String* special,
5658 sinkchar* sink,
5659 FixedArray* fixed_array,
5660 int array_length) {
5661 int position = 0;
5662 for (int i = 0; i < array_length; i++) {
5663 Object* element = fixed_array->get(i);
5664 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005665 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005666 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005667 int pos;
5668 int len;
5669 if (encoded_slice > 0) {
5670 // Position and length encoded in one smi.
5671 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5672 len = StringBuilderSubstringLength::decode(encoded_slice);
5673 } else {
5674 // Position and length encoded in two smis.
5675 Object* obj = fixed_array->get(++i);
5676 ASSERT(obj->IsSmi());
5677 pos = Smi::cast(obj)->value();
5678 len = -encoded_slice;
5679 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005680 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005681 sink + position,
5682 pos,
5683 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005684 position += len;
5685 } else {
5686 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005687 int element_length = string->length();
5688 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005689 position += element_length;
5690 }
5691 }
5692}
5693
5694
lrn@chromium.org303ada72010-10-27 09:33:13 +00005695static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005696 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005697 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005698 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005699 if (!args[1]->IsSmi()) {
5700 Top::context()->mark_out_of_memory();
5701 return Failure::OutOfMemoryException();
5702 }
5703 int array_length = Smi::cast(args[1])->value();
5704 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005705
5706 // This assumption is used by the slice encoding in one or two smis.
5707 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5708
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005709 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005710 if (!array->HasFastElements()) {
5711 return Top::Throw(Heap::illegal_argument_symbol());
5712 }
5713 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005714 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005715 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005716 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005717
5718 if (array_length == 0) {
5719 return Heap::empty_string();
5720 } else if (array_length == 1) {
5721 Object* first = fixed_array->get(0);
5722 if (first->IsString()) return first;
5723 }
5724
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005725 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005726 int position = 0;
5727 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005728 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005729 Object* elt = fixed_array->get(i);
5730 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005731 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005732 int smi_value = Smi::cast(elt)->value();
5733 int pos;
5734 int len;
5735 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005736 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005737 pos = StringBuilderSubstringPosition::decode(smi_value);
5738 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005739 } else {
5740 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005741 len = -smi_value;
5742 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005743 i++;
5744 if (i >= array_length) {
5745 return Top::Throw(Heap::illegal_argument_symbol());
5746 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005747 Object* next_smi = fixed_array->get(i);
5748 if (!next_smi->IsSmi()) {
5749 return Top::Throw(Heap::illegal_argument_symbol());
5750 }
5751 pos = Smi::cast(next_smi)->value();
5752 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005753 return Top::Throw(Heap::illegal_argument_symbol());
5754 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005755 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005756 ASSERT(pos >= 0);
5757 ASSERT(len >= 0);
5758 if (pos > special_length || len > special_length - pos) {
5759 return Top::Throw(Heap::illegal_argument_symbol());
5760 }
5761 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005762 } else if (elt->IsString()) {
5763 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005764 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005765 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005766 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005767 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005768 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005769 } else {
5770 return Top::Throw(Heap::illegal_argument_symbol());
5771 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005772 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005773 Top::context()->mark_out_of_memory();
5774 return Failure::OutOfMemoryException();
5775 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005776 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005777 }
5778
5779 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005780 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005781
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005782 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005783 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5784 if (!maybe_object->ToObject(&object)) return maybe_object;
5785 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005786 SeqAsciiString* answer = SeqAsciiString::cast(object);
5787 StringBuilderConcatHelper(special,
5788 answer->GetChars(),
5789 fixed_array,
5790 array_length);
5791 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005792 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005793 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5794 if (!maybe_object->ToObject(&object)) return maybe_object;
5795 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005796 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5797 StringBuilderConcatHelper(special,
5798 answer->GetChars(),
5799 fixed_array,
5800 array_length);
5801 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005803}
5804
5805
lrn@chromium.org303ada72010-10-27 09:33:13 +00005806static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005807 NoHandleAllocation ha;
5808 ASSERT(args.length() == 2);
5809
5810 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5811 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5812 return Heap::NumberFromInt32(x | y);
5813}
5814
5815
lrn@chromium.org303ada72010-10-27 09:33:13 +00005816static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005817 NoHandleAllocation ha;
5818 ASSERT(args.length() == 2);
5819
5820 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5821 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5822 return Heap::NumberFromInt32(x & y);
5823}
5824
5825
lrn@chromium.org303ada72010-10-27 09:33:13 +00005826static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005827 NoHandleAllocation ha;
5828 ASSERT(args.length() == 2);
5829
5830 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5831 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5832 return Heap::NumberFromInt32(x ^ y);
5833}
5834
5835
lrn@chromium.org303ada72010-10-27 09:33:13 +00005836static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005837 NoHandleAllocation ha;
5838 ASSERT(args.length() == 1);
5839
5840 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5841 return Heap::NumberFromInt32(~x);
5842}
5843
5844
lrn@chromium.org303ada72010-10-27 09:33:13 +00005845static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005846 NoHandleAllocation ha;
5847 ASSERT(args.length() == 2);
5848
5849 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5850 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5851 return Heap::NumberFromInt32(x << (y & 0x1f));
5852}
5853
5854
lrn@chromium.org303ada72010-10-27 09:33:13 +00005855static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005856 NoHandleAllocation ha;
5857 ASSERT(args.length() == 2);
5858
5859 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5860 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5861 return Heap::NumberFromUint32(x >> (y & 0x1f));
5862}
5863
5864
lrn@chromium.org303ada72010-10-27 09:33:13 +00005865static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005866 NoHandleAllocation ha;
5867 ASSERT(args.length() == 2);
5868
5869 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5870 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5871 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5872}
5873
5874
lrn@chromium.org303ada72010-10-27 09:33:13 +00005875static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005876 NoHandleAllocation ha;
5877 ASSERT(args.length() == 2);
5878
5879 CONVERT_DOUBLE_CHECKED(x, args[0]);
5880 CONVERT_DOUBLE_CHECKED(y, args[1]);
5881 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5882 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5883 if (x == y) return Smi::FromInt(EQUAL);
5884 Object* result;
5885 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5886 result = Smi::FromInt(EQUAL);
5887 } else {
5888 result = Smi::FromInt(NOT_EQUAL);
5889 }
5890 return result;
5891}
5892
5893
lrn@chromium.org303ada72010-10-27 09:33:13 +00005894static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895 NoHandleAllocation ha;
5896 ASSERT(args.length() == 2);
5897
5898 CONVERT_CHECKED(String, x, args[0]);
5899 CONVERT_CHECKED(String, y, args[1]);
5900
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005901 bool not_equal = !x->Equals(y);
5902 // This is slightly convoluted because the value that signifies
5903 // equality is 0 and inequality is 1 so we have to negate the result
5904 // from String::Equals.
5905 ASSERT(not_equal == 0 || not_equal == 1);
5906 STATIC_CHECK(EQUAL == 0);
5907 STATIC_CHECK(NOT_EQUAL == 1);
5908 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005909}
5910
5911
lrn@chromium.org303ada72010-10-27 09:33:13 +00005912static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005913 NoHandleAllocation ha;
5914 ASSERT(args.length() == 3);
5915
5916 CONVERT_DOUBLE_CHECKED(x, args[0]);
5917 CONVERT_DOUBLE_CHECKED(y, args[1]);
5918 if (isnan(x) || isnan(y)) return args[2];
5919 if (x == y) return Smi::FromInt(EQUAL);
5920 if (isless(x, y)) return Smi::FromInt(LESS);
5921 return Smi::FromInt(GREATER);
5922}
5923
5924
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005925// Compare two Smis as if they were converted to strings and then
5926// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005927static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005928 NoHandleAllocation ha;
5929 ASSERT(args.length() == 2);
5930
5931 // Arrays for the individual characters of the two Smis. Smis are
5932 // 31 bit integers and 10 decimal digits are therefore enough.
5933 static int x_elms[10];
5934 static int y_elms[10];
5935
5936 // Extract the integer values from the Smis.
5937 CONVERT_CHECKED(Smi, x, args[0]);
5938 CONVERT_CHECKED(Smi, y, args[1]);
5939 int x_value = x->value();
5940 int y_value = y->value();
5941
5942 // If the integers are equal so are the string representations.
5943 if (x_value == y_value) return Smi::FromInt(EQUAL);
5944
5945 // If one of the integers are zero the normal integer order is the
5946 // same as the lexicographic order of the string representations.
5947 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5948
ager@chromium.org32912102009-01-16 10:38:43 +00005949 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005950 // smallest because the char code of '-' is less than the char code
5951 // of any digit. Otherwise, we make both values positive.
5952 if (x_value < 0 || y_value < 0) {
5953 if (y_value >= 0) return Smi::FromInt(LESS);
5954 if (x_value >= 0) return Smi::FromInt(GREATER);
5955 x_value = -x_value;
5956 y_value = -y_value;
5957 }
5958
5959 // Convert the integers to arrays of their decimal digits.
5960 int x_index = 0;
5961 int y_index = 0;
5962 while (x_value > 0) {
5963 x_elms[x_index++] = x_value % 10;
5964 x_value /= 10;
5965 }
5966 while (y_value > 0) {
5967 y_elms[y_index++] = y_value % 10;
5968 y_value /= 10;
5969 }
5970
5971 // Loop through the arrays of decimal digits finding the first place
5972 // where they differ.
5973 while (--x_index >= 0 && --y_index >= 0) {
5974 int diff = x_elms[x_index] - y_elms[y_index];
5975 if (diff != 0) return Smi::FromInt(diff);
5976 }
5977
5978 // If one array is a suffix of the other array, the longest array is
5979 // the representation of the largest of the Smis in the
5980 // lexicographic ordering.
5981 return Smi::FromInt(x_index - y_index);
5982}
5983
5984
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005985static Object* StringInputBufferCompare(String* x, String* y) {
5986 static StringInputBuffer bufx;
5987 static StringInputBuffer bufy;
5988 bufx.Reset(x);
5989 bufy.Reset(y);
5990 while (bufx.has_more() && bufy.has_more()) {
5991 int d = bufx.GetNext() - bufy.GetNext();
5992 if (d < 0) return Smi::FromInt(LESS);
5993 else if (d > 0) return Smi::FromInt(GREATER);
5994 }
5995
5996 // x is (non-trivial) prefix of y:
5997 if (bufy.has_more()) return Smi::FromInt(LESS);
5998 // y is prefix of x:
5999 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6000}
6001
6002
6003static Object* FlatStringCompare(String* x, String* y) {
6004 ASSERT(x->IsFlat());
6005 ASSERT(y->IsFlat());
6006 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6007 int prefix_length = x->length();
6008 if (y->length() < prefix_length) {
6009 prefix_length = y->length();
6010 equal_prefix_result = Smi::FromInt(GREATER);
6011 } else if (y->length() > prefix_length) {
6012 equal_prefix_result = Smi::FromInt(LESS);
6013 }
6014 int r;
6015 if (x->IsAsciiRepresentation()) {
6016 Vector<const char> x_chars = x->ToAsciiVector();
6017 if (y->IsAsciiRepresentation()) {
6018 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006019 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006020 } else {
6021 Vector<const uc16> y_chars = y->ToUC16Vector();
6022 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6023 }
6024 } else {
6025 Vector<const uc16> x_chars = x->ToUC16Vector();
6026 if (y->IsAsciiRepresentation()) {
6027 Vector<const char> y_chars = y->ToAsciiVector();
6028 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6029 } else {
6030 Vector<const uc16> y_chars = y->ToUC16Vector();
6031 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6032 }
6033 }
6034 Object* result;
6035 if (r == 0) {
6036 result = equal_prefix_result;
6037 } else {
6038 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6039 }
6040 ASSERT(result == StringInputBufferCompare(x, y));
6041 return result;
6042}
6043
6044
lrn@chromium.org303ada72010-10-27 09:33:13 +00006045static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046 NoHandleAllocation ha;
6047 ASSERT(args.length() == 2);
6048
6049 CONVERT_CHECKED(String, x, args[0]);
6050 CONVERT_CHECKED(String, y, args[1]);
6051
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006052 Counters::string_compare_runtime.Increment();
6053
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054 // A few fast case tests before we flatten.
6055 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006056 if (y->length() == 0) {
6057 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006058 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006059 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060 return Smi::FromInt(LESS);
6061 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006062
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006063 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006064 if (d < 0) return Smi::FromInt(LESS);
6065 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006066
lrn@chromium.org303ada72010-10-27 09:33:13 +00006067 Object* obj;
6068 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
6069 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6070 }
6071 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
6072 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6073 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006074
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006075 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
6076 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006077}
6078
6079
lrn@chromium.org303ada72010-10-27 09:33:13 +00006080static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006081 NoHandleAllocation ha;
6082 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006083 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006084
6085 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006086 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006087}
6088
6089
lrn@chromium.org303ada72010-10-27 09:33:13 +00006090static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006091 NoHandleAllocation ha;
6092 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006093 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006094
6095 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006096 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006097}
6098
6099
lrn@chromium.org303ada72010-10-27 09:33:13 +00006100static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006101 NoHandleAllocation ha;
6102 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006103 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006104
6105 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006106 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006107}
6108
6109
lrn@chromium.org303ada72010-10-27 09:33:13 +00006110static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006111 NoHandleAllocation ha;
6112 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006113 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006114
6115 CONVERT_DOUBLE_CHECKED(x, args[0]);
6116 CONVERT_DOUBLE_CHECKED(y, args[1]);
6117 double result;
6118 if (isinf(x) && isinf(y)) {
6119 // Make sure that the result in case of two infinite arguments
6120 // is a multiple of Pi / 4. The sign of the result is determined
6121 // by the first argument (x) and the sign of the second argument
6122 // determines the multiplier: one or three.
6123 static double kPiDividedBy4 = 0.78539816339744830962;
6124 int multiplier = (x < 0) ? -1 : 1;
6125 if (y < 0) multiplier *= 3;
6126 result = multiplier * kPiDividedBy4;
6127 } else {
6128 result = atan2(x, y);
6129 }
6130 return Heap::AllocateHeapNumber(result);
6131}
6132
6133
lrn@chromium.org303ada72010-10-27 09:33:13 +00006134static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006135 NoHandleAllocation ha;
6136 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006137 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006138
6139 CONVERT_DOUBLE_CHECKED(x, args[0]);
6140 return Heap::NumberFromDouble(ceiling(x));
6141}
6142
6143
lrn@chromium.org303ada72010-10-27 09:33:13 +00006144static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006145 NoHandleAllocation ha;
6146 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006147 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006148
6149 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006150 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006151}
6152
6153
lrn@chromium.org303ada72010-10-27 09:33:13 +00006154static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006155 NoHandleAllocation ha;
6156 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006157 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006158
6159 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006160 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006161}
6162
6163
lrn@chromium.org303ada72010-10-27 09:33:13 +00006164static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006165 NoHandleAllocation ha;
6166 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006167 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006168
6169 CONVERT_DOUBLE_CHECKED(x, args[0]);
6170 return Heap::NumberFromDouble(floor(x));
6171}
6172
6173
lrn@chromium.org303ada72010-10-27 09:33:13 +00006174static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006175 NoHandleAllocation ha;
6176 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006177 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006178
6179 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006180 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006181}
6182
6183
lrn@chromium.org303ada72010-10-27 09:33:13 +00006184static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006185 NoHandleAllocation ha;
6186 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006187 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006188
6189 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006190
6191 // If the second argument is a smi, it is much faster to call the
6192 // custom powi() function than the generic pow().
6193 if (args[1]->IsSmi()) {
6194 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006195 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006196 }
6197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006198 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006199 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006200}
6201
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006202// Fast version of Math.pow if we know that y is not an integer and
6203// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006204static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006205 NoHandleAllocation ha;
6206 ASSERT(args.length() == 2);
6207 CONVERT_DOUBLE_CHECKED(x, args[0]);
6208 CONVERT_DOUBLE_CHECKED(y, args[1]);
6209 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006210 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006211 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006212 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006213 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006214 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006215 }
6216}
6217
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006218
lrn@chromium.org303ada72010-10-27 09:33:13 +00006219static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220 NoHandleAllocation ha;
6221 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006222 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006223
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006224 if (!args[0]->IsHeapNumber()) {
6225 // Must be smi. Return the argument unchanged for all the other types
6226 // to make fuzz-natives test happy.
6227 return args[0];
6228 }
6229
6230 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6231
6232 double value = number->value();
6233 int exponent = number->get_exponent();
6234 int sign = number->get_sign();
6235
6236 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6237 // should be rounded to 2^30, which is not smi.
6238 if (!sign && exponent <= kSmiValueSize - 3) {
6239 return Smi::FromInt(static_cast<int>(value + 0.5));
6240 }
6241
6242 // If the magnitude is big enough, there's no place for fraction part. If we
6243 // try to add 0.5 to this number, 1.0 will be added instead.
6244 if (exponent >= 52) {
6245 return number;
6246 }
6247
6248 if (sign && value >= -0.5) return Heap::minus_zero_value();
6249
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006250 // Do not call NumberFromDouble() to avoid extra checks.
6251 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252}
6253
6254
lrn@chromium.org303ada72010-10-27 09:33:13 +00006255static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006256 NoHandleAllocation ha;
6257 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006258 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006259
6260 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006261 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262}
6263
6264
lrn@chromium.org303ada72010-10-27 09:33:13 +00006265static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266 NoHandleAllocation ha;
6267 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006268 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006269
6270 CONVERT_DOUBLE_CHECKED(x, args[0]);
6271 return Heap::AllocateHeapNumber(sqrt(x));
6272}
6273
6274
lrn@chromium.org303ada72010-10-27 09:33:13 +00006275static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006276 NoHandleAllocation ha;
6277 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006278 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006279
6280 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006281 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006282}
6283
6284
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006285static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006286 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6287 181, 212, 243, 273, 304, 334};
6288 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6289 182, 213, 244, 274, 305, 335};
6290
6291 year += month / 12;
6292 month %= 12;
6293 if (month < 0) {
6294 year--;
6295 month += 12;
6296 }
6297
6298 ASSERT(month >= 0);
6299 ASSERT(month < 12);
6300
6301 // year_delta is an arbitrary number such that:
6302 // a) year_delta = -1 (mod 400)
6303 // b) year + year_delta > 0 for years in the range defined by
6304 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6305 // Jan 1 1970. This is required so that we don't run into integer
6306 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006307 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006308 // operations.
6309 static const int year_delta = 399999;
6310 static const int base_day = 365 * (1970 + year_delta) +
6311 (1970 + year_delta) / 4 -
6312 (1970 + year_delta) / 100 +
6313 (1970 + year_delta) / 400;
6314
6315 int year1 = year + year_delta;
6316 int day_from_year = 365 * year1 +
6317 year1 / 4 -
6318 year1 / 100 +
6319 year1 / 400 -
6320 base_day;
6321
6322 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006323 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006324 }
6325
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006326 return day_from_year + day_from_month_leap[month] + day - 1;
6327}
6328
6329
lrn@chromium.org303ada72010-10-27 09:33:13 +00006330static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006331 NoHandleAllocation ha;
6332 ASSERT(args.length() == 3);
6333
6334 CONVERT_SMI_CHECKED(year, args[0]);
6335 CONVERT_SMI_CHECKED(month, args[1]);
6336 CONVERT_SMI_CHECKED(date, args[2]);
6337
6338 return Smi::FromInt(MakeDay(year, month, date));
6339}
6340
6341
6342static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6343static const int kDaysIn4Years = 4 * 365 + 1;
6344static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6345static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6346static const int kDays1970to2000 = 30 * 365 + 7;
6347static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6348 kDays1970to2000;
6349static const int kYearsOffset = 400000;
6350
6351static const char kDayInYear[] = {
6352 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6353 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6354 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6355 22, 23, 24, 25, 26, 27, 28,
6356 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6357 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6358 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6359 22, 23, 24, 25, 26, 27, 28, 29, 30,
6360 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6361 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6362 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6363 22, 23, 24, 25, 26, 27, 28, 29, 30,
6364 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6365 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6366 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6367 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6368 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6369 22, 23, 24, 25, 26, 27, 28, 29, 30,
6370 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6371 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6372 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6373 22, 23, 24, 25, 26, 27, 28, 29, 30,
6374 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6375 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6376
6377 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6378 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6379 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6380 22, 23, 24, 25, 26, 27, 28,
6381 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6382 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6383 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6384 22, 23, 24, 25, 26, 27, 28, 29, 30,
6385 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6386 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6387 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6388 22, 23, 24, 25, 26, 27, 28, 29, 30,
6389 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6390 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6391 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6392 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6393 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6394 22, 23, 24, 25, 26, 27, 28, 29, 30,
6395 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6396 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6397 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6398 22, 23, 24, 25, 26, 27, 28, 29, 30,
6399 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6400 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6401
6402 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6403 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6404 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6405 22, 23, 24, 25, 26, 27, 28, 29,
6406 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6407 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6408 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6409 22, 23, 24, 25, 26, 27, 28, 29, 30,
6410 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6411 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6412 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6413 22, 23, 24, 25, 26, 27, 28, 29, 30,
6414 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6415 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6416 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6417 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6418 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6419 22, 23, 24, 25, 26, 27, 28, 29, 30,
6420 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6421 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6422 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6423 22, 23, 24, 25, 26, 27, 28, 29, 30,
6424 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6425 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6426
6427 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6428 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6429 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6430 22, 23, 24, 25, 26, 27, 28,
6431 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6432 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6433 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6434 22, 23, 24, 25, 26, 27, 28, 29, 30,
6435 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6436 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6437 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6438 22, 23, 24, 25, 26, 27, 28, 29, 30,
6439 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6440 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6441 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6442 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6443 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6444 22, 23, 24, 25, 26, 27, 28, 29, 30,
6445 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6446 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6447 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6448 22, 23, 24, 25, 26, 27, 28, 29, 30,
6449 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6450 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6451
6452static const char kMonthInYear[] = {
6453 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6454 0, 0, 0, 0, 0, 0,
6455 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6456 1, 1, 1,
6457 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6458 2, 2, 2, 2, 2, 2,
6459 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6460 3, 3, 3, 3, 3,
6461 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6462 4, 4, 4, 4, 4, 4,
6463 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6464 5, 5, 5, 5, 5,
6465 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6466 6, 6, 6, 6, 6, 6,
6467 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6468 7, 7, 7, 7, 7, 7,
6469 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6470 8, 8, 8, 8, 8,
6471 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6472 9, 9, 9, 9, 9, 9,
6473 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6474 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6475 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6476 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6477
6478 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6479 0, 0, 0, 0, 0, 0,
6480 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6481 1, 1, 1,
6482 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6483 2, 2, 2, 2, 2, 2,
6484 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6485 3, 3, 3, 3, 3,
6486 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6487 4, 4, 4, 4, 4, 4,
6488 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6489 5, 5, 5, 5, 5,
6490 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6491 6, 6, 6, 6, 6, 6,
6492 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6493 7, 7, 7, 7, 7, 7,
6494 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6495 8, 8, 8, 8, 8,
6496 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6497 9, 9, 9, 9, 9, 9,
6498 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6499 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6500 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6501 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6502
6503 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6504 0, 0, 0, 0, 0, 0,
6505 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6506 1, 1, 1, 1,
6507 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6508 2, 2, 2, 2, 2, 2,
6509 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6510 3, 3, 3, 3, 3,
6511 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6512 4, 4, 4, 4, 4, 4,
6513 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6514 5, 5, 5, 5, 5,
6515 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6516 6, 6, 6, 6, 6, 6,
6517 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6518 7, 7, 7, 7, 7, 7,
6519 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6520 8, 8, 8, 8, 8,
6521 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6522 9, 9, 9, 9, 9, 9,
6523 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6524 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6525 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6526 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6527
6528 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6529 0, 0, 0, 0, 0, 0,
6530 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6531 1, 1, 1,
6532 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6533 2, 2, 2, 2, 2, 2,
6534 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
6535 3, 3, 3, 3, 3,
6536 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
6537 4, 4, 4, 4, 4, 4,
6538 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6539 5, 5, 5, 5, 5,
6540 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6541 6, 6, 6, 6, 6, 6,
6542 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
6543 7, 7, 7, 7, 7, 7,
6544 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
6545 8, 8, 8, 8, 8,
6546 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
6547 9, 9, 9, 9, 9, 9,
6548 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6549 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6550 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6551 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6552
6553
6554// This function works for dates from 1970 to 2099.
6555static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006556 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006557#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006558 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006559#endif
6560
6561 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6562 date %= kDaysIn4Years;
6563
6564 month = kMonthInYear[date];
6565 day = kDayInYear[date];
6566
6567 ASSERT(MakeDay(year, month, day) == save_date);
6568}
6569
6570
6571static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006572 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006573#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006574 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006575#endif
6576
6577 date += kDaysOffset;
6578 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6579 date %= kDaysIn400Years;
6580
6581 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6582
6583 date--;
6584 int yd1 = date / kDaysIn100Years;
6585 date %= kDaysIn100Years;
6586 year += 100 * yd1;
6587
6588 date++;
6589 int yd2 = date / kDaysIn4Years;
6590 date %= kDaysIn4Years;
6591 year += 4 * yd2;
6592
6593 date--;
6594 int yd3 = date / 365;
6595 date %= 365;
6596 year += yd3;
6597
6598 bool is_leap = (!yd1 || yd2) && !yd3;
6599
6600 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006601 ASSERT(is_leap || (date >= 0));
6602 ASSERT((date < 365) || (is_leap && (date < 366)));
6603 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6604 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6605 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006606
6607 if (is_leap) {
6608 day = kDayInYear[2*365 + 1 + date];
6609 month = kMonthInYear[2*365 + 1 + date];
6610 } else {
6611 day = kDayInYear[date];
6612 month = kMonthInYear[date];
6613 }
6614
6615 ASSERT(MakeDay(year, month, day) == save_date);
6616}
6617
6618
6619static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006620 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006621 if (date >= 0 && date < 32 * kDaysIn4Years) {
6622 DateYMDFromTimeAfter1970(date, year, month, day);
6623 } else {
6624 DateYMDFromTimeSlow(date, year, month, day);
6625 }
6626}
6627
6628
lrn@chromium.org303ada72010-10-27 09:33:13 +00006629static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006630 NoHandleAllocation ha;
6631 ASSERT(args.length() == 2);
6632
6633 CONVERT_DOUBLE_CHECKED(t, args[0]);
6634 CONVERT_CHECKED(JSArray, res_array, args[1]);
6635
6636 int year, month, day;
6637 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6638
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006639 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6640 FixedArray* elms = FixedArray::cast(res_array->elements());
6641 RUNTIME_ASSERT(elms->length() == 3);
6642
6643 elms->set(0, Smi::FromInt(year));
6644 elms->set(1, Smi::FromInt(month));
6645 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006646
6647 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006648}
6649
6650
lrn@chromium.org303ada72010-10-27 09:33:13 +00006651static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006652 NoHandleAllocation ha;
6653 ASSERT(args.length() == 3);
6654
6655 JSFunction* callee = JSFunction::cast(args[0]);
6656 Object** parameters = reinterpret_cast<Object**>(args[1]);
6657 const int length = Smi::cast(args[2])->value();
6658
lrn@chromium.org303ada72010-10-27 09:33:13 +00006659 Object* result;
6660 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6661 if (!maybe_result->ToObject(&result)) return maybe_result;
6662 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006663 // Allocate the elements if needed.
6664 if (length > 0) {
6665 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006666 Object* obj;
6667 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6668 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6669 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006670
6671 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006672 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6673 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006674 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006675
6676 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006677 for (int i = 0; i < length; i++) {
6678 array->set(i, *--parameters, mode);
6679 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006680 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006681 }
6682 return result;
6683}
6684
6685
lrn@chromium.org303ada72010-10-27 09:33:13 +00006686static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006687 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006688 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006689 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006690 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006691 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006692
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006693 // Allocate global closures in old space and allocate local closures
6694 // in new space. Additionally pretenure closures that are assigned
6695 // directly to properties.
6696 pretenure = pretenure || (context->global_context() == *context);
6697 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006698 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006699 Factory::NewFunctionFromSharedFunctionInfo(shared,
6700 context,
6701 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702 return *result;
6703}
6704
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006705
lrn@chromium.org303ada72010-10-27 09:33:13 +00006706static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006707 HandleScope scope;
6708 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006709 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006710 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006711
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006712 // Second argument is either null or an array of bound arguments.
6713 FixedArray* bound_args = NULL;
6714 int bound_argc = 0;
6715 if (!args[1]->IsNull()) {
6716 CONVERT_ARG_CHECKED(JSArray, params, 1);
6717 RUNTIME_ASSERT(params->HasFastElements());
6718 bound_args = FixedArray::cast(params->elements());
6719 bound_argc = Smi::cast(params->length())->value();
6720 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006721
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006722 // Find frame containing arguments passed to the caller.
6723 JavaScriptFrameIterator it;
6724 JavaScriptFrame* frame = it.frame();
6725 ASSERT(!frame->is_optimized());
6726 it.AdvanceToArgumentsFrame();
6727 frame = it.frame();
6728 int argc = frame->GetProvidedParametersCount();
6729
6730 // Prepend bound arguments to caller's arguments.
6731 int total_argc = bound_argc + argc;
6732 SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
6733 for (int i = 0; i < bound_argc; i++) {
6734 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006735 param_data[i] = val.location();
6736 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006737 for (int i = 0; i < argc; i++) {
6738 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
6739 param_data[bound_argc + i] = val.location();
6740 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006741
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006742 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006743 Handle<Object> result =
6744 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006745 if (exception) {
6746 return Failure::Exception();
6747 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006748
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006749 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006750 return *result;
6751}
6752
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006754static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006755 Handle<Object> prototype = Factory::null_value();
6756 if (function->has_instance_prototype()) {
6757 prototype = Handle<Object>(function->instance_prototype());
6758 }
6759 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006760 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006761 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006762 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006763 function->shared()->set_construct_stub(
6764 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006765 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006766 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006767}
6768
6769
lrn@chromium.org303ada72010-10-27 09:33:13 +00006770static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006771 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772 ASSERT(args.length() == 1);
6773
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006774 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006775
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006776 // If the constructor isn't a proper function we throw a type error.
6777 if (!constructor->IsJSFunction()) {
6778 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6779 Handle<Object> type_error =
6780 Factory::NewTypeError("not_constructor", arguments);
6781 return Top::Throw(*type_error);
6782 }
6783
6784 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006785
6786 // If function should not have prototype, construction is not allowed. In this
6787 // case generated code bailouts here, since function has no initial_map.
6788 if (!function->should_have_prototype()) {
6789 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6790 Handle<Object> type_error =
6791 Factory::NewTypeError("not_constructor", arguments);
6792 return Top::Throw(*type_error);
6793 }
6794
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006795#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006796 // Handle stepping into constructors if step into is active.
6797 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006798 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006799 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006800#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006801
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006802 if (function->has_initial_map()) {
6803 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804 // The 'Function' function ignores the receiver object when
6805 // called using 'new' and creates a new JSFunction object that
6806 // is returned. The receiver object is only used for error
6807 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006808 // JSFunction. Factory::NewJSObject() should not be used to
6809 // allocate JSFunctions since it does not properly initialize
6810 // the shared part of the function. Since the receiver is
6811 // ignored anyway, we use the global object as the receiver
6812 // instead of a new JSFunction object. This way, errors are
6813 // reported the same way whether or not 'Function' is called
6814 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815 return Top::context()->global();
6816 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006817 }
6818
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006819 // The function should be compiled for the optimization hints to be
6820 // available. We cannot use EnsureCompiled because that forces a
6821 // compilation through the shared function info which makes it
6822 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006823 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006824 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006825
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006826 if (!function->has_initial_map() &&
6827 shared->IsInobjectSlackTrackingInProgress()) {
6828 // The tracking is already in progress for another function. We can only
6829 // track one initial_map at a time, so we force the completion before the
6830 // function is called as a constructor for the first time.
6831 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006832 }
6833
6834 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006835 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006836 // Delay setting the stub if inobject slack tracking is in progress.
6837 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6838 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006839 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006840
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006841 Counters::constructed_objects.Increment();
6842 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006843
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006844 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006845}
6846
6847
lrn@chromium.org303ada72010-10-27 09:33:13 +00006848static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006849 HandleScope scope;
6850 ASSERT(args.length() == 1);
6851
6852 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6853 function->shared()->CompleteInobjectSlackTracking();
6854 TrySettingInlineConstructStub(function);
6855
6856 return Heap::undefined_value();
6857}
6858
6859
lrn@chromium.org303ada72010-10-27 09:33:13 +00006860static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006861 HandleScope scope;
6862 ASSERT(args.length() == 1);
6863
6864 Handle<JSFunction> function = args.at<JSFunction>(0);
6865#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006866 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006867 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006868 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006869 PrintF("]\n");
6870 }
6871#endif
6872
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006873 // Compile the target function. Here we compile using CompileLazyInLoop in
6874 // order to get the optimized version. This helps code like delta-blue
6875 // that calls performance-critical routines through constructors. A
6876 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6877 // direct call. Since the in-loop tracking takes place through CallICs
6878 // this means that things called through constructors are never known to
6879 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006880 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006881 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006882 return Failure::Exception();
6883 }
6884
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006885 // All done. Return the compiled code.
6886 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006887 return function->code();
6888}
6889
6890
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006891static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6892 HandleScope scope;
6893 ASSERT(args.length() == 1);
6894 Handle<JSFunction> function = args.at<JSFunction>(0);
6895 // If the function is not optimizable or debugger is active continue using the
6896 // code from the full compiler.
6897 if (!function->shared()->code()->optimizable() ||
6898 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006899 if (FLAG_trace_opt) {
6900 PrintF("[failed to optimize ");
6901 function->PrintName();
6902 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
6903 function->shared()->code()->optimizable() ? "T" : "F",
6904 Debug::has_break_points() ? "T" : "F");
6905 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006906 function->ReplaceCode(function->shared()->code());
6907 return function->code();
6908 }
6909 if (CompileOptimized(function, AstNode::kNoNumber)) {
6910 return function->code();
6911 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006912 if (FLAG_trace_opt) {
6913 PrintF("[failed to optimize ");
6914 function->PrintName();
6915 PrintF(": optimized compilation failed]\n");
6916 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006917 function->ReplaceCode(function->shared()->code());
6918 return Failure::Exception();
6919}
6920
6921
6922static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
6923 HandleScope scope;
6924 ASSERT(args.length() == 1);
6925 RUNTIME_ASSERT(args[0]->IsSmi());
6926 Deoptimizer::BailoutType type =
6927 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
6928 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6929 ASSERT(Heap::IsAllocationAllowed());
6930 int frames = deoptimizer->output_count();
6931
6932 JavaScriptFrameIterator it;
6933 JavaScriptFrame* frame = NULL;
6934 for (int i = 0; i < frames; i++) {
6935 if (i != 0) it.Advance();
6936 frame = it.frame();
6937 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
6938 }
6939 delete deoptimizer;
6940
6941 RUNTIME_ASSERT(frame->function()->IsJSFunction());
6942 Handle<JSFunction> function(JSFunction::cast(frame->function()));
6943 Handle<Object> arguments;
6944 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00006945 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006946 if (arguments.is_null()) {
6947 // FunctionGetArguments can't throw an exception, so cast away the
6948 // doubt with an assert.
6949 arguments = Handle<Object>(
6950 Accessors::FunctionGetArguments(*function,
6951 NULL)->ToObjectUnchecked());
6952 ASSERT(*arguments != Heap::null_value());
6953 ASSERT(*arguments != Heap::undefined_value());
6954 }
6955 frame->SetExpression(i, *arguments);
6956 }
6957 }
6958
6959 CompilationCache::MarkForLazyOptimizing(function);
6960 if (type == Deoptimizer::EAGER) {
6961 RUNTIME_ASSERT(function->IsOptimized());
6962 } else {
6963 RUNTIME_ASSERT(!function->IsOptimized());
6964 }
6965
6966 // Avoid doing too much work when running with --always-opt and keep
6967 // the optimized code around.
6968 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
6969 return Heap::undefined_value();
6970 }
6971
6972 // Count the number of optimized activations of the function.
6973 int activations = 0;
6974 while (!it.done()) {
6975 JavaScriptFrame* frame = it.frame();
6976 if (frame->is_optimized() && frame->function() == *function) {
6977 activations++;
6978 }
6979 it.Advance();
6980 }
6981
6982 // TODO(kasperl): For now, we cannot support removing the optimized
6983 // code when we have recursive invocations of the same function.
6984 if (activations == 0) {
6985 if (FLAG_trace_deopt) {
6986 PrintF("[removing optimized code for: ");
6987 function->PrintName();
6988 PrintF("]\n");
6989 }
6990 function->ReplaceCode(function->shared()->code());
6991 }
6992 return Heap::undefined_value();
6993}
6994
6995
6996static MaybeObject* Runtime_NotifyOSR(Arguments args) {
6997 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6998 delete deoptimizer;
6999 return Heap::undefined_value();
7000}
7001
7002
7003static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
7004 HandleScope scope;
7005 ASSERT(args.length() == 1);
7006 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7007 if (!function->IsOptimized()) return Heap::undefined_value();
7008
7009 Deoptimizer::DeoptimizeFunction(*function);
7010
7011 return Heap::undefined_value();
7012}
7013
7014
7015static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
7016 HandleScope scope;
7017 ASSERT(args.length() == 1);
7018 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7019
7020 // We're not prepared to handle a function with arguments object.
7021 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7022
7023 // We have hit a back edge in an unoptimized frame for a function that was
7024 // selected for on-stack replacement. Find the unoptimized code object.
7025 Handle<Code> unoptimized(function->shared()->code());
7026 // Keep track of whether we've succeeded in optimizing.
7027 bool succeeded = unoptimized->optimizable();
7028 if (succeeded) {
7029 // If we are trying to do OSR when there are already optimized
7030 // activations of the function, it means (a) the function is directly or
7031 // indirectly recursive and (b) an optimized invocation has been
7032 // deoptimized so that we are currently in an unoptimized activation.
7033 // Check for optimized activations of this function.
7034 JavaScriptFrameIterator it;
7035 while (succeeded && !it.done()) {
7036 JavaScriptFrame* frame = it.frame();
7037 succeeded = !frame->is_optimized() || frame->function() != *function;
7038 it.Advance();
7039 }
7040 }
7041
7042 int ast_id = AstNode::kNoNumber;
7043 if (succeeded) {
7044 // The top JS function is this one, the PC is somewhere in the
7045 // unoptimized code.
7046 JavaScriptFrameIterator it;
7047 JavaScriptFrame* frame = it.frame();
7048 ASSERT(frame->function() == *function);
7049 ASSERT(frame->code() == *unoptimized);
7050 ASSERT(unoptimized->contains(frame->pc()));
7051
7052 // Use linear search of the unoptimized code's stack check table to find
7053 // the AST id matching the PC.
7054 Address start = unoptimized->instruction_start();
7055 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007056 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007057 uint32_t table_length = Memory::uint32_at(table_cursor);
7058 table_cursor += kIntSize;
7059 for (unsigned i = 0; i < table_length; ++i) {
7060 // Table entries are (AST id, pc offset) pairs.
7061 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7062 if (pc_offset == target_pc_offset) {
7063 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7064 break;
7065 }
7066 table_cursor += 2 * kIntSize;
7067 }
7068 ASSERT(ast_id != AstNode::kNoNumber);
7069 if (FLAG_trace_osr) {
7070 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7071 function->PrintName();
7072 PrintF("]\n");
7073 }
7074
7075 // Try to compile the optimized code. A true return value from
7076 // CompileOptimized means that compilation succeeded, not necessarily
7077 // that optimization succeeded.
7078 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
7079 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7080 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007081 if (data->OsrPcOffset()->value() >= 0) {
7082 if (FLAG_trace_osr) {
7083 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007084 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007085 }
7086 ASSERT(data->OsrAstId()->value() == ast_id);
7087 } else {
7088 // We may never generate the desired OSR entry if we emit an
7089 // early deoptimize.
7090 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007091 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007092 } else {
7093 succeeded = false;
7094 }
7095 }
7096
7097 // Revert to the original stack checks in the original unoptimized code.
7098 if (FLAG_trace_osr) {
7099 PrintF("[restoring original stack checks in ");
7100 function->PrintName();
7101 PrintF("]\n");
7102 }
7103 StackCheckStub check_stub;
7104 Handle<Code> check_code = check_stub.GetCode();
7105 Handle<Code> replacement_code(
7106 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007107 Deoptimizer::RevertStackCheckCode(*unoptimized,
7108 *check_code,
7109 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007110
7111 // Allow OSR only at nesting level zero again.
7112 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7113
7114 // If the optimization attempt succeeded, return the AST id tagged as a
7115 // smi. This tells the builtin that we need to translate the unoptimized
7116 // frame to an optimized one.
7117 if (succeeded) {
7118 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7119 return Smi::FromInt(ast_id);
7120 } else {
7121 return Smi::FromInt(-1);
7122 }
7123}
7124
7125
lrn@chromium.org303ada72010-10-27 09:33:13 +00007126static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007127 HandleScope scope;
7128 ASSERT(args.length() == 1);
7129 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7130 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7131}
7132
7133
lrn@chromium.org303ada72010-10-27 09:33:13 +00007134static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007135 HandleScope scope;
7136 ASSERT(args.length() == 1);
7137 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7138 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7139}
7140
7141
lrn@chromium.org303ada72010-10-27 09:33:13 +00007142static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007144 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007145
kasper.lund7276f142008-07-30 08:49:36 +00007146 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007147 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007148 Object* result;
7149 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
7150 if (!maybe_result->ToObject(&result)) return maybe_result;
7151 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007152
7153 Top::set_context(Context::cast(result));
7154
kasper.lund7276f142008-07-30 08:49:36 +00007155 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007156}
7157
lrn@chromium.org303ada72010-10-27 09:33:13 +00007158
7159MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7160 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007161 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007162 Object* js_object = object;
7163 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007164 MaybeObject* maybe_js_object = js_object->ToObject();
7165 if (!maybe_js_object->ToObject(&js_object)) {
7166 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7167 return maybe_js_object;
7168 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007169 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007170 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007171 Handle<Object> result =
7172 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7173 return Top::Throw(*result);
7174 }
7175 }
7176
lrn@chromium.org303ada72010-10-27 09:33:13 +00007177 Object* result;
7178 { MaybeObject* maybe_result =
7179 Heap::AllocateWithContext(Top::context(),
7180 JSObject::cast(js_object),
7181 is_catch_context);
7182 if (!maybe_result->ToObject(&result)) return maybe_result;
7183 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007184
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007185 Context* context = Context::cast(result);
7186 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007187
kasper.lund7276f142008-07-30 08:49:36 +00007188 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007189}
7190
7191
lrn@chromium.org303ada72010-10-27 09:33:13 +00007192static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007193 NoHandleAllocation ha;
7194 ASSERT(args.length() == 1);
7195 return PushContextHelper(args[0], false);
7196}
7197
7198
lrn@chromium.org303ada72010-10-27 09:33:13 +00007199static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007200 NoHandleAllocation ha;
7201 ASSERT(args.length() == 1);
7202 return PushContextHelper(args[0], true);
7203}
7204
7205
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007206static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007207 HandleScope scope;
7208 ASSERT(args.length() == 2);
7209
7210 CONVERT_ARG_CHECKED(Context, context, 0);
7211 CONVERT_ARG_CHECKED(String, name, 1);
7212
7213 int index;
7214 PropertyAttributes attributes;
7215 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007216 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007217
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007218 // If the slot was not found the result is true.
7219 if (holder.is_null()) {
7220 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007221 }
7222
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007223 // If the slot was found in a context, it should be DONT_DELETE.
7224 if (holder->IsContext()) {
7225 return Heap::false_value();
7226 }
7227
7228 // The slot was found in a JSObject, either a context extension object,
7229 // the global object, or an arguments object. Try to delete it
7230 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7231 // which allows deleting all parameters in functions that mention
7232 // 'arguments', we do this even for the case of slots found on an
7233 // arguments object. The slot was found on an arguments object if the
7234 // index is non-negative.
7235 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7236 if (index >= 0) {
7237 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7238 } else {
7239 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7240 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007241}
7242
7243
ager@chromium.orga1645e22009-09-09 19:27:10 +00007244// A mechanism to return a pair of Object pointers in registers (if possible).
7245// How this is achieved is calling convention-dependent.
7246// All currently supported x86 compiles uses calling conventions that are cdecl
7247// variants where a 64-bit value is returned in two 32-bit registers
7248// (edx:eax on ia32, r1:r0 on ARM).
7249// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7250// In Win64 calling convention, a struct of two pointers is returned in memory,
7251// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007252#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007253struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007254 MaybeObject* x;
7255 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007256};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007257
lrn@chromium.org303ada72010-10-27 09:33:13 +00007258static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007259 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007260 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7261 // In Win64 they are assigned to a hidden first argument.
7262 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007263}
7264#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007265typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007266static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007267 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007268 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007269}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007270#endif
7271
7272
lrn@chromium.org303ada72010-10-27 09:33:13 +00007273static inline MaybeObject* Unhole(MaybeObject* x,
7274 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007275 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7276 USE(attributes);
7277 return x->IsTheHole() ? Heap::undefined_value() : x;
7278}
7279
7280
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007281static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7282 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007283 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007284 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007285 JSFunction* context_extension_function =
7286 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007287 // If the holder isn't a context extension object, we just return it
7288 // as the receiver. This allows arguments objects to be used as
7289 // receivers, but only if they are put in the context scope chain
7290 // explicitly via a with-statement.
7291 Object* constructor = holder->map()->constructor();
7292 if (constructor != context_extension_function) return holder;
7293 // Fall back to using the global object as the receiver if the
7294 // property turns out to be a local variable allocated in a context
7295 // extension object - introduced via eval.
7296 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007297}
7298
7299
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007300static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007302 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007304 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007305 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007306 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007308 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007309
7310 int index;
7311 PropertyAttributes attributes;
7312 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007313 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007315 // If the index is non-negative, the slot has been found in a local
7316 // variable or a parameter. Read it from the context object or the
7317 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007319 // If the "property" we were looking for is a local variable or an
7320 // argument in a context, the receiver is the global object; see
7321 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7322 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007323 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007324 ? Context::cast(*holder)->get(index)
7325 : JSObject::cast(*holder)->GetElement(index);
7326 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327 }
7328
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007329 // If the holder is found, we read the property from it.
7330 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007331 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007332 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007333 JSObject* receiver;
7334 if (object->IsGlobalObject()) {
7335 receiver = GlobalObject::cast(object)->global_receiver();
7336 } else if (context->is_exception_holder(*holder)) {
7337 receiver = Top::context()->global()->global_receiver();
7338 } else {
7339 receiver = ComputeReceiverForNonGlobal(object);
7340 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007341 // No need to unhole the value here. This is taken care of by the
7342 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007343 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007344 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007345 }
7346
7347 if (throw_error) {
7348 // The property doesn't exist - throw exception.
7349 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007350 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351 return MakePair(Top::Throw(*reference_error), NULL);
7352 } else {
7353 // The property doesn't exist - return undefined
7354 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7355 }
7356}
7357
7358
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007359static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360 return LoadContextSlotHelper(args, true);
7361}
7362
7363
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007364static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007365 return LoadContextSlotHelper(args, false);
7366}
7367
7368
lrn@chromium.org303ada72010-10-27 09:33:13 +00007369static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370 HandleScope scope;
7371 ASSERT(args.length() == 3);
7372
7373 Handle<Object> value(args[0]);
7374 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007375 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376
7377 int index;
7378 PropertyAttributes attributes;
7379 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007380 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381
7382 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007383 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384 // Ignore if read_only variable.
7385 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007386 // Context is a fixed array and set cannot fail.
7387 Context::cast(*holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007388 }
7389 } else {
7390 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007391 Handle<Object> result =
7392 SetElement(Handle<JSObject>::cast(holder), index, value);
7393 if (result.is_null()) {
7394 ASSERT(Top::has_pending_exception());
7395 return Failure::Exception();
7396 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397 }
7398 return *value;
7399 }
7400
7401 // Slow case: The property is not in a FixedArray context.
7402 // It is either in an JSObject extension context or it was not found.
7403 Handle<JSObject> context_ext;
7404
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007405 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007406 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007407 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408 } else {
7409 // The property was not found. It needs to be stored in the global context.
7410 ASSERT(attributes == ABSENT);
7411 attributes = NONE;
7412 context_ext = Handle<JSObject>(Top::context()->global());
7413 }
7414
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007415 // Set the property, but ignore if read_only variable on the context
7416 // extension object itself.
7417 if ((attributes & READ_ONLY) == 0 ||
7418 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007419 RETURN_IF_EMPTY_HANDLE(SetProperty(context_ext, name, value, NONE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420 }
7421 return *value;
7422}
7423
7424
lrn@chromium.org303ada72010-10-27 09:33:13 +00007425static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007426 HandleScope scope;
7427 ASSERT(args.length() == 1);
7428
7429 return Top::Throw(args[0]);
7430}
7431
7432
lrn@chromium.org303ada72010-10-27 09:33:13 +00007433static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007434 HandleScope scope;
7435 ASSERT(args.length() == 1);
7436
7437 return Top::ReThrow(args[0]);
7438}
7439
7440
lrn@chromium.org303ada72010-10-27 09:33:13 +00007441static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007442 ASSERT_EQ(0, args.length());
7443 return Top::PromoteScheduledException();
7444}
7445
7446
lrn@chromium.org303ada72010-10-27 09:33:13 +00007447static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007448 HandleScope scope;
7449 ASSERT(args.length() == 1);
7450
7451 Handle<Object> name(args[0]);
7452 Handle<Object> reference_error =
7453 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7454 return Top::Throw(*reference_error);
7455}
7456
7457
lrn@chromium.org303ada72010-10-27 09:33:13 +00007458static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007459 NoHandleAllocation na;
7460 return Top::StackOverflow();
7461}
7462
7463
lrn@chromium.org303ada72010-10-27 09:33:13 +00007464static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007465 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007466
7467 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007468 if (StackGuard::IsStackOverflow()) {
7469 return Runtime_StackOverflow(args);
7470 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007471
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007472 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473}
7474
7475
7476// NOTE: These PrintXXX functions are defined for all builds (not just
7477// DEBUG builds) because we may want to be able to trace function
7478// calls in all modes.
7479static void PrintString(String* str) {
7480 // not uncommon to have empty strings
7481 if (str->length() > 0) {
7482 SmartPointer<char> s =
7483 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7484 PrintF("%s", *s);
7485 }
7486}
7487
7488
7489static void PrintObject(Object* obj) {
7490 if (obj->IsSmi()) {
7491 PrintF("%d", Smi::cast(obj)->value());
7492 } else if (obj->IsString() || obj->IsSymbol()) {
7493 PrintString(String::cast(obj));
7494 } else if (obj->IsNumber()) {
7495 PrintF("%g", obj->Number());
7496 } else if (obj->IsFailure()) {
7497 PrintF("<failure>");
7498 } else if (obj->IsUndefined()) {
7499 PrintF("<undefined>");
7500 } else if (obj->IsNull()) {
7501 PrintF("<null>");
7502 } else if (obj->IsTrue()) {
7503 PrintF("<true>");
7504 } else if (obj->IsFalse()) {
7505 PrintF("<false>");
7506 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007507 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007508 }
7509}
7510
7511
7512static int StackSize() {
7513 int n = 0;
7514 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7515 return n;
7516}
7517
7518
7519static void PrintTransition(Object* result) {
7520 // indentation
7521 { const int nmax = 80;
7522 int n = StackSize();
7523 if (n <= nmax)
7524 PrintF("%4d:%*s", n, n, "");
7525 else
7526 PrintF("%4d:%*s", n, nmax, "...");
7527 }
7528
7529 if (result == NULL) {
7530 // constructor calls
7531 JavaScriptFrameIterator it;
7532 JavaScriptFrame* frame = it.frame();
7533 if (frame->IsConstructor()) PrintF("new ");
7534 // function name
7535 Object* fun = frame->function();
7536 if (fun->IsJSFunction()) {
7537 PrintObject(JSFunction::cast(fun)->shared()->name());
7538 } else {
7539 PrintObject(fun);
7540 }
7541 // function arguments
7542 // (we are intentionally only printing the actually
7543 // supplied parameters, not all parameters required)
7544 PrintF("(this=");
7545 PrintObject(frame->receiver());
7546 const int length = frame->GetProvidedParametersCount();
7547 for (int i = 0; i < length; i++) {
7548 PrintF(", ");
7549 PrintObject(frame->GetParameter(i));
7550 }
7551 PrintF(") {\n");
7552
7553 } else {
7554 // function result
7555 PrintF("} -> ");
7556 PrintObject(result);
7557 PrintF("\n");
7558 }
7559}
7560
7561
lrn@chromium.org303ada72010-10-27 09:33:13 +00007562static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007563 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007564 NoHandleAllocation ha;
7565 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007566 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007567}
7568
7569
lrn@chromium.org303ada72010-10-27 09:33:13 +00007570static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007571 NoHandleAllocation ha;
7572 PrintTransition(args[0]);
7573 return args[0]; // return TOS
7574}
7575
7576
lrn@chromium.org303ada72010-10-27 09:33:13 +00007577static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578 NoHandleAllocation ha;
7579 ASSERT(args.length() == 1);
7580
7581#ifdef DEBUG
7582 if (args[0]->IsString()) {
7583 // If we have a string, assume it's a code "marker"
7584 // and print some interesting cpu debugging info.
7585 JavaScriptFrameIterator it;
7586 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007587 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7588 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007589 } else {
7590 PrintF("DebugPrint: ");
7591 }
7592 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007593 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007594 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007595 HeapObject::cast(args[0])->map()->Print();
7596 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007597#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007598 // ShortPrint is available in release mode. Print is not.
7599 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007600#endif
7601 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007602 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007603
7604 return args[0]; // return TOS
7605}
7606
7607
lrn@chromium.org303ada72010-10-27 09:33:13 +00007608static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007609 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007610 NoHandleAllocation ha;
7611 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007612 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007613}
7614
7615
lrn@chromium.org303ada72010-10-27 09:33:13 +00007616static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007617 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007618 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007619
7620 // According to ECMA-262, section 15.9.1, page 117, the precision of
7621 // the number in a Date object representing a particular instant in
7622 // time is milliseconds. Therefore, we floor the result of getting
7623 // the OS time.
7624 double millis = floor(OS::TimeCurrentMillis());
7625 return Heap::NumberFromDouble(millis);
7626}
7627
7628
lrn@chromium.org303ada72010-10-27 09:33:13 +00007629static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007630 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007631 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007632
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007633 CONVERT_ARG_CHECKED(String, str, 0);
7634 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007635
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007636 CONVERT_ARG_CHECKED(JSArray, output, 1);
7637 RUNTIME_ASSERT(output->HasFastElements());
7638
7639 AssertNoAllocation no_allocation;
7640
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007641 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007642 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7643 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007644 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007645 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007646 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007647 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007648 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7649 }
7650
7651 if (result) {
7652 return *output;
7653 } else {
7654 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007655 }
7656}
7657
7658
lrn@chromium.org303ada72010-10-27 09:33:13 +00007659static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007660 NoHandleAllocation ha;
7661 ASSERT(args.length() == 1);
7662
7663 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007664 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007665 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7666}
7667
7668
lrn@chromium.org303ada72010-10-27 09:33:13 +00007669static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007670 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007671 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007672
7673 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7674}
7675
7676
lrn@chromium.org303ada72010-10-27 09:33:13 +00007677static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007678 NoHandleAllocation ha;
7679 ASSERT(args.length() == 1);
7680
7681 CONVERT_DOUBLE_CHECKED(x, args[0]);
7682 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7683}
7684
7685
lrn@chromium.org303ada72010-10-27 09:33:13 +00007686static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007687 ASSERT(args.length() == 1);
7688 Object* global = args[0];
7689 if (!global->IsJSGlobalObject()) return Heap::null_value();
7690 return JSGlobalObject::cast(global)->global_receiver();
7691}
7692
7693
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007694static MaybeObject* Runtime_ParseJson(Arguments args) {
7695 HandleScope scope;
7696 ASSERT_EQ(1, args.length());
7697 CONVERT_ARG_CHECKED(String, source, 0);
7698
7699 Handle<Object> result = JsonParser::Parse(source);
7700 if (result.is_null()) {
7701 // Syntax error or stack overflow in scanner.
7702 ASSERT(Top::has_pending_exception());
7703 return Failure::Exception();
7704 }
7705 return *result;
7706}
7707
7708
lrn@chromium.org303ada72010-10-27 09:33:13 +00007709static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007710 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007711 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007712 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007713
ager@chromium.org381abbb2009-02-25 13:23:22 +00007714 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007715 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007716 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7717 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007718 true,
7719 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007720 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007721 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007722 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007723 return *fun;
7724}
7725
7726
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007727static ObjectPair CompileGlobalEval(Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007728 Handle<Object> receiver,
7729 StrictModeFlag mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007730 // Deal with a normal eval call with a string argument. Compile it
7731 // and return the compiled function bound in the local context.
7732 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7733 source,
7734 Handle<Context>(Top::context()),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007735 Top::context()->IsGlobalContext(),
7736 mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007737 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7738 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7739 shared,
7740 Handle<Context>(Top::context()),
7741 NOT_TENURED);
7742 return MakePair(*compiled, *receiver);
7743}
7744
7745
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007746static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007747 ASSERT(args.length() == 4);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007748 if (!args[0]->IsJSFunction()) {
7749 return MakePair(Top::ThrowIllegalOperation(), NULL);
7750 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007751
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007752 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007753 Handle<JSFunction> callee = args.at<JSFunction>(0);
7754 Handle<Object> receiver; // Will be overwritten.
7755
7756 // Compute the calling context.
7757 Handle<Context> context = Handle<Context>(Top::context());
7758#ifdef DEBUG
7759 // Make sure Top::context() agrees with the old code that traversed
7760 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007761 StackFrameLocator locator;
7762 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007763 ASSERT(Context::cast(frame->context()) == *context);
7764#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007765
7766 // Find where the 'eval' symbol is bound. It is unaliased only if
7767 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007768 int index = -1;
7769 PropertyAttributes attributes = ABSENT;
7770 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007771 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7772 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007773 // Stop search when eval is found or when the global context is
7774 // reached.
7775 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007776 if (context->is_function_context()) {
7777 context = Handle<Context>(Context::cast(context->closure()->context()));
7778 } else {
7779 context = Handle<Context>(context->previous());
7780 }
7781 }
7782
iposva@chromium.org245aa852009-02-10 00:49:54 +00007783 // If eval could not be resolved, it has been deleted and we need to
7784 // throw a reference error.
7785 if (attributes == ABSENT) {
7786 Handle<Object> name = Factory::eval_symbol();
7787 Handle<Object> reference_error =
7788 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007789 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007790 }
7791
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007792 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007793 // 'eval' is not bound in the global context. Just call the function
7794 // with the given arguments. This is not necessarily the global eval.
7795 if (receiver->IsContext()) {
7796 context = Handle<Context>::cast(receiver);
7797 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007798 } else if (receiver->IsJSContextExtensionObject()) {
7799 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007800 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007801 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007802 }
7803
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007804 // 'eval' is bound in the global context, but it may have been overwritten.
7805 // Compare it to the builtin 'GlobalEval' function to make sure.
7806 if (*callee != Top::global_context()->global_eval_fun() ||
7807 !args[1]->IsString()) {
7808 return MakePair(*callee, Top::context()->global()->global_receiver());
7809 }
7810
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007811 ASSERT(args[3]->IsSmi());
7812 return CompileGlobalEval(args.at<String>(1),
7813 args.at<Object>(2),
7814 static_cast<StrictModeFlag>(
7815 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007816}
7817
7818
7819static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007820 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007821 if (!args[0]->IsJSFunction()) {
7822 return MakePair(Top::ThrowIllegalOperation(), NULL);
7823 }
7824
7825 HandleScope scope;
7826 Handle<JSFunction> callee = args.at<JSFunction>(0);
7827
7828 // 'eval' is bound in the global context, but it may have been overwritten.
7829 // Compare it to the builtin 'GlobalEval' function to make sure.
7830 if (*callee != Top::global_context()->global_eval_fun() ||
7831 !args[1]->IsString()) {
7832 return MakePair(*callee, Top::context()->global()->global_receiver());
7833 }
7834
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007835 ASSERT(args[3]->IsSmi());
7836 return CompileGlobalEval(args.at<String>(1),
7837 args.at<Object>(2),
7838 static_cast<StrictModeFlag>(
7839 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007840}
7841
7842
lrn@chromium.org303ada72010-10-27 09:33:13 +00007843static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007844 // This utility adjusts the property attributes for newly created Function
7845 // object ("new Function(...)") by changing the map.
7846 // All it does is changing the prototype property to enumerable
7847 // as specified in ECMA262, 15.3.5.2.
7848 HandleScope scope;
7849 ASSERT(args.length() == 1);
7850 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7851 ASSERT(func->map()->instance_type() ==
7852 Top::function_instance_map()->instance_type());
7853 ASSERT(func->map()->instance_size() ==
7854 Top::function_instance_map()->instance_size());
7855 func->set_map(*Top::function_instance_map());
7856 return *func;
7857}
7858
7859
lrn@chromium.org303ada72010-10-27 09:33:13 +00007860static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007861 // Allocate a block of memory in NewSpace (filled with a filler).
7862 // Use as fallback for allocation in generated code when NewSpace
7863 // is full.
7864 ASSERT(args.length() == 1);
7865 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7866 int size = size_smi->value();
7867 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7868 RUNTIME_ASSERT(size > 0);
7869 static const int kMinFreeNewSpaceAfterGC =
7870 Heap::InitialSemiSpaceSize() * 3/4;
7871 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007872 Object* allocation;
7873 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7874 if (maybe_allocation->ToObject(&allocation)) {
7875 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7876 }
7877 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007878 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007879}
7880
7881
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007882// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007883// array. Returns true if the element was pushed on the stack and
7884// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007885static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007886 ASSERT(args.length() == 2);
7887 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007888 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007889 RUNTIME_ASSERT(array->HasFastElements());
7890 int length = Smi::cast(array->length())->value();
7891 FixedArray* elements = FixedArray::cast(array->elements());
7892 for (int i = 0; i < length; i++) {
7893 if (elements->get(i) == element) return Heap::false_value();
7894 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007895 Object* obj;
7896 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7897 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7898 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007899 return Heap::true_value();
7900}
7901
7902
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007903/**
7904 * A simple visitor visits every element of Array's.
7905 * The backend storage can be a fixed array for fast elements case,
7906 * or a dictionary for sparse array. Since Dictionary is a subtype
7907 * of FixedArray, the class can be used by both fast and slow cases.
7908 * The second parameter of the constructor, fast_elements, specifies
7909 * whether the storage is a FixedArray or Dictionary.
7910 *
7911 * An index limit is used to deal with the situation that a result array
7912 * length overflows 32-bit non-negative integer.
7913 */
7914class ArrayConcatVisitor {
7915 public:
7916 ArrayConcatVisitor(Handle<FixedArray> storage,
7917 uint32_t index_limit,
7918 bool fast_elements) :
7919 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007920 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007921
7922 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007923 if (i >= index_limit_ - index_offset_) return;
7924 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007925
7926 if (fast_elements_) {
7927 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7928 storage_->set(index, *elm);
7929
7930 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007931 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7932 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007933 Factory::DictionaryAtNumberPut(dict, index, elm);
7934 if (!result.is_identical_to(dict))
7935 storage_ = result;
7936 }
7937 }
7938
7939 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007940 if (index_limit_ - index_offset_ < delta) {
7941 index_offset_ = index_limit_;
7942 } else {
7943 index_offset_ += delta;
7944 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007945 }
7946
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007947 Handle<FixedArray> storage() { return storage_; }
7948
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007949 private:
7950 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007951 // Limit on the accepted indices. Elements with indices larger than the
7952 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007953 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007954 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007955 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007956 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007957};
7958
7959
ager@chromium.org3811b432009-10-28 14:53:37 +00007960template<class ExternalArrayClass, class ElementType>
7961static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7962 bool elements_are_ints,
7963 bool elements_are_guaranteed_smis,
7964 uint32_t range,
7965 ArrayConcatVisitor* visitor) {
7966 Handle<ExternalArrayClass> array(
7967 ExternalArrayClass::cast(receiver->elements()));
7968 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7969
7970 if (visitor != NULL) {
7971 if (elements_are_ints) {
7972 if (elements_are_guaranteed_smis) {
7973 for (uint32_t j = 0; j < len; j++) {
7974 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7975 visitor->visit(j, e);
7976 }
7977 } else {
7978 for (uint32_t j = 0; j < len; j++) {
7979 int64_t val = static_cast<int64_t>(array->get(j));
7980 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7981 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7982 visitor->visit(j, e);
7983 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007984 Handle<Object> e =
7985 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007986 visitor->visit(j, e);
7987 }
7988 }
7989 }
7990 } else {
7991 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007992 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007993 visitor->visit(j, e);
7994 }
7995 }
7996 }
7997
7998 return len;
7999}
8000
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008001/**
8002 * A helper function that visits elements of a JSObject. Only elements
8003 * whose index between 0 and range (exclusive) are visited.
8004 *
8005 * If the third parameter, visitor, is not NULL, the visitor is called
8006 * with parameters, 'visitor_index_offset + element index' and the element.
8007 *
8008 * It returns the number of visisted elements.
8009 */
8010static uint32_t IterateElements(Handle<JSObject> receiver,
8011 uint32_t range,
8012 ArrayConcatVisitor* visitor) {
8013 uint32_t num_of_elements = 0;
8014
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008015 switch (receiver->GetElementsKind()) {
8016 case JSObject::FAST_ELEMENTS: {
8017 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8018 uint32_t len = elements->length();
8019 if (range < len) {
8020 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008021 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008022
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008023 for (uint32_t j = 0; j < len; j++) {
8024 Handle<Object> e(elements->get(j));
8025 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008026 num_of_elements++;
8027 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008028 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008029 }
8030 }
8031 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008032 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008033 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008034 case JSObject::PIXEL_ELEMENTS: {
8035 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8036 uint32_t len = pixels->length();
8037 if (range < len) {
8038 len = range;
8039 }
8040
8041 for (uint32_t j = 0; j < len; j++) {
8042 num_of_elements++;
8043 if (visitor != NULL) {
8044 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8045 visitor->visit(j, e);
8046 }
8047 }
8048 break;
8049 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008050 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8051 num_of_elements =
8052 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8053 receiver, true, true, range, visitor);
8054 break;
8055 }
8056 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8057 num_of_elements =
8058 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8059 receiver, true, true, range, visitor);
8060 break;
8061 }
8062 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8063 num_of_elements =
8064 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8065 receiver, true, true, range, visitor);
8066 break;
8067 }
8068 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8069 num_of_elements =
8070 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8071 receiver, true, true, range, visitor);
8072 break;
8073 }
8074 case JSObject::EXTERNAL_INT_ELEMENTS: {
8075 num_of_elements =
8076 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8077 receiver, true, false, range, visitor);
8078 break;
8079 }
8080 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8081 num_of_elements =
8082 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8083 receiver, true, false, range, visitor);
8084 break;
8085 }
8086 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8087 num_of_elements =
8088 IterateExternalArrayElements<ExternalFloatArray, float>(
8089 receiver, false, false, range, visitor);
8090 break;
8091 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008092 case JSObject::DICTIONARY_ELEMENTS: {
8093 Handle<NumberDictionary> dict(receiver->element_dictionary());
8094 uint32_t capacity = dict->Capacity();
8095 for (uint32_t j = 0; j < capacity; j++) {
8096 Handle<Object> k(dict->KeyAt(j));
8097 if (dict->IsKey(*k)) {
8098 ASSERT(k->IsNumber());
8099 uint32_t index = static_cast<uint32_t>(k->Number());
8100 if (index < range) {
8101 num_of_elements++;
8102 if (visitor) {
8103 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
8104 }
8105 }
8106 }
8107 }
8108 break;
8109 }
8110 default:
8111 UNREACHABLE();
8112 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008113 }
8114
8115 return num_of_elements;
8116}
8117
8118
8119/**
8120 * A helper function that visits elements of an Array object, and elements
8121 * on its prototypes.
8122 *
8123 * Elements on prototypes are visited first, and only elements whose indices
8124 * less than Array length are visited.
8125 *
8126 * If a ArrayConcatVisitor object is given, the visitor is called with
8127 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008128 *
8129 * The returned number of elements is an upper bound on the actual number
8130 * of elements added. If the same element occurs in more than one object
8131 * in the array's prototype chain, it will be counted more than once, but
8132 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008133 */
8134static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
8135 ArrayConcatVisitor* visitor) {
8136 uint32_t range = static_cast<uint32_t>(array->length()->Number());
8137 Handle<Object> obj = array;
8138
8139 static const int kEstimatedPrototypes = 3;
8140 List< Handle<JSObject> > objects(kEstimatedPrototypes);
8141
8142 // Visit prototype first. If an element on the prototype is shadowed by
8143 // the inheritor using the same index, the ArrayConcatVisitor visits
8144 // the prototype element before the shadowing element.
8145 // The visitor can simply overwrite the old value by new value using
8146 // the same index. This follows Array::concat semantics.
8147 while (!obj->IsNull()) {
8148 objects.Add(Handle<JSObject>::cast(obj));
8149 obj = Handle<Object>(obj->GetPrototype());
8150 }
8151
8152 uint32_t nof_elements = 0;
8153 for (int i = objects.length() - 1; i >= 0; i--) {
8154 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008155 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008156 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008157
8158 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
8159 nof_elements = JSObject::kMaxElementCount;
8160 } else {
8161 nof_elements += encountered_elements;
8162 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008163 }
8164
8165 return nof_elements;
8166}
8167
8168
8169/**
8170 * A helper function of Runtime_ArrayConcat.
8171 *
8172 * The first argument is an Array of arrays and objects. It is the
8173 * same as the arguments array of Array::concat JS function.
8174 *
8175 * If an argument is an Array object, the function visits array
8176 * elements. If an argument is not an Array object, the function
8177 * visits the object as if it is an one-element array.
8178 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008179 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008180 * non-negative number is used as new length. For example, if one
8181 * array length is 2^32 - 1, second array length is 1, the
8182 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008183 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
8184 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008185 */
8186static uint32_t IterateArguments(Handle<JSArray> arguments,
8187 ArrayConcatVisitor* visitor) {
8188 uint32_t visited_elements = 0;
8189 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8190
8191 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008192 Object *element;
8193 MaybeObject* maybe_element = arguments->GetElement(i);
8194 // This if() is not expected to fail, but we have the check in the
8195 // interest of hardening the runtime calls.
8196 if (maybe_element->ToObject(&element)) {
8197 Handle<Object> obj(element);
8198 if (obj->IsJSArray()) {
8199 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8200 uint32_t len = static_cast<uint32_t>(array->length()->Number());
8201 uint32_t nof_elements =
8202 IterateArrayAndPrototypeElements(array, visitor);
8203 // Total elements of array and its prototype chain can be more than
8204 // the array length, but ArrayConcat can only concatenate at most
8205 // the array length number of elements. We use the length as an estimate
8206 // for the actual number of elements added.
8207 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8208 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8209 visited_elements = JSArray::kMaxElementCount;
8210 } else {
8211 visited_elements += added_elements;
8212 }
8213 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008214 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008215 if (visitor) {
8216 visitor->visit(0, obj);
8217 visitor->increase_index_offset(1);
8218 }
8219 if (visited_elements < JSArray::kMaxElementCount) {
8220 visited_elements++;
8221 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008222 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008223 }
8224 }
8225 return visited_elements;
8226}
8227
8228
8229/**
8230 * Array::concat implementation.
8231 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008232 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8233 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008234 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008235static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008236 ASSERT(args.length() == 1);
8237 HandleScope handle_scope;
8238
8239 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8240 Handle<JSArray> arguments(arg_arrays);
8241
8242 // Pass 1: estimate the number of elements of the result
8243 // (it could be more than real numbers if prototype has elements).
8244 uint32_t result_length = 0;
8245 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8246
8247 { AssertNoAllocation nogc;
8248 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008249 Object* obj;
8250 MaybeObject* maybe_object = arguments->GetElement(i);
8251 // This if() is not expected to fail, but we have the check in the
8252 // interest of hardening the runtime calls.
8253 if (maybe_object->ToObject(&obj)) {
8254 uint32_t length_estimate;
8255 if (obj->IsJSArray()) {
8256 length_estimate =
8257 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8258 } else {
8259 length_estimate = 1;
8260 }
8261 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8262 result_length = JSObject::kMaxElementCount;
8263 break;
8264 }
8265 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008266 }
8267 }
8268 }
8269
8270 // Allocate an empty array, will set length and content later.
8271 Handle<JSArray> result = Factory::NewJSArray(0);
8272
8273 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8274 // If estimated number of elements is more than half of length, a
8275 // fixed array (fast case) is more time and space-efficient than a
8276 // dictionary.
8277 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8278
8279 Handle<FixedArray> storage;
8280 if (fast_case) {
8281 // The backing storage array must have non-existing elements to
8282 // preserve holes across concat operations.
8283 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008284 Handle<Map> fast_map =
8285 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8286 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008287 } else {
8288 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8289 uint32_t at_least_space_for = estimate_nof_elements +
8290 (estimate_nof_elements >> 2);
8291 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008292 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008293 Handle<Map> slow_map =
8294 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8295 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008296 }
8297
8298 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8299
8300 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8301
8302 IterateArguments(arguments, &visitor);
8303
8304 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008305 // Please note the storage might have changed in the visitor.
8306 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008307
8308 return *result;
8309}
8310
8311
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008312// This will not allocate (flatten the string), but it may run
8313// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008314static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008315 NoHandleAllocation ha;
8316 ASSERT(args.length() == 1);
8317
8318 CONVERT_CHECKED(String, string, args[0]);
8319 StringInputBuffer buffer(string);
8320 while (buffer.has_more()) {
8321 uint16_t character = buffer.GetNext();
8322 PrintF("%c", character);
8323 }
8324 return string;
8325}
8326
ager@chromium.org5ec48922009-05-05 07:25:34 +00008327// Moves all own elements of an object, that are below a limit, to positions
8328// starting at zero. All undefined values are placed after non-undefined values,
8329// and are followed by non-existing element. Does not change the length
8330// property.
8331// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008332static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008333 ASSERT(args.length() == 2);
8334 CONVERT_CHECKED(JSObject, object, args[0]);
8335 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8336 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008337}
8338
8339
8340// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008341static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008342 ASSERT(args.length() == 2);
8343 CONVERT_CHECKED(JSArray, from, args[0]);
8344 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008345 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008346 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008347 if (new_elements->map() == Heap::fixed_array_map() ||
8348 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008349 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008350 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008351 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008352 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008353 Object* new_map;
8354 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008355 to->set_map(Map::cast(new_map));
8356 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008357 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008358 Object* obj;
8359 { MaybeObject* maybe_obj = from->ResetElements();
8360 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8361 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008362 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008363 return to;
8364}
8365
8366
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008367// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008368static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008369 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008370 CONVERT_CHECKED(JSObject, object, args[0]);
8371 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008372 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008373 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008374 } else if (object->IsJSArray()) {
8375 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008376 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008377 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008378 }
8379}
8380
8381
lrn@chromium.org303ada72010-10-27 09:33:13 +00008382static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008383 HandleScope handle_scope;
8384
8385 ASSERT_EQ(3, args.length());
8386
ager@chromium.orgac091b72010-05-05 07:34:42 +00008387 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008388 Handle<Object> key1 = args.at<Object>(1);
8389 Handle<Object> key2 = args.at<Object>(2);
8390
8391 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008392 if (!key1->ToArrayIndex(&index1)
8393 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008394 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008395 }
8396
ager@chromium.orgac091b72010-05-05 07:34:42 +00008397 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8398 Handle<Object> tmp1 = GetElement(jsobject, index1);
8399 Handle<Object> tmp2 = GetElement(jsobject, index2);
8400
8401 SetElement(jsobject, index1, tmp2);
8402 SetElement(jsobject, index2, tmp1);
8403
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008404 return Heap::undefined_value();
8405}
8406
8407
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008408// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008409// might have elements. Can either return keys (positive integers) or
8410// intervals (pair of a negative integer (-start-1) followed by a
8411// positive (length)) or undefined values.
8412// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008413static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008414 ASSERT(args.length() == 2);
8415 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008416 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008417 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008418 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008419 // Create an array and get all the keys into it, then remove all the
8420 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008421 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008422 int keys_length = keys->length();
8423 for (int i = 0; i < keys_length; i++) {
8424 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008425 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008426 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008427 // Zap invalid keys.
8428 keys->set_undefined(i);
8429 }
8430 }
8431 return *Factory::NewJSArrayWithElements(keys);
8432 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008433 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008434 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8435 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008436 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008437 uint32_t actual_length =
8438 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008439 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008440 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008441 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008442 single_interval->set(1, *length_object);
8443 return *Factory::NewJSArrayWithElements(single_interval);
8444 }
8445}
8446
8447
8448// DefineAccessor takes an optional final argument which is the
8449// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8450// to the way accessors are implemented, it is set for both the getter
8451// and setter on the first call to DefineAccessor and ignored on
8452// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008453static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008454 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8455 // Compute attributes.
8456 PropertyAttributes attributes = NONE;
8457 if (args.length() == 5) {
8458 CONVERT_CHECKED(Smi, attrs, args[4]);
8459 int value = attrs->value();
8460 // Only attribute bits should be set.
8461 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8462 attributes = static_cast<PropertyAttributes>(value);
8463 }
8464
8465 CONVERT_CHECKED(JSObject, obj, args[0]);
8466 CONVERT_CHECKED(String, name, args[1]);
8467 CONVERT_CHECKED(Smi, flag, args[2]);
8468 CONVERT_CHECKED(JSFunction, fun, args[3]);
8469 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8470}
8471
8472
lrn@chromium.org303ada72010-10-27 09:33:13 +00008473static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008474 ASSERT(args.length() == 3);
8475 CONVERT_CHECKED(JSObject, obj, args[0]);
8476 CONVERT_CHECKED(String, name, args[1]);
8477 CONVERT_CHECKED(Smi, flag, args[2]);
8478 return obj->LookupAccessor(name, flag->value() == 0);
8479}
8480
8481
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008482#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008483static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008484 ASSERT(args.length() == 0);
8485 return Execution::DebugBreakHelper();
8486}
8487
8488
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008489// Helper functions for wrapping and unwrapping stack frame ids.
8490static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008491 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008492 return Smi::FromInt(id >> 2);
8493}
8494
8495
8496static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8497 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8498}
8499
8500
8501// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008502// args[0]: debug event listener function to set or null or undefined for
8503// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008504// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008505static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008506 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008507 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8508 args[0]->IsUndefined() ||
8509 args[0]->IsNull());
8510 Handle<Object> callback = args.at<Object>(0);
8511 Handle<Object> data = args.at<Object>(1);
8512 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008513
8514 return Heap::undefined_value();
8515}
8516
8517
lrn@chromium.org303ada72010-10-27 09:33:13 +00008518static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008519 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008520 StackGuard::DebugBreak();
8521 return Heap::undefined_value();
8522}
8523
8524
lrn@chromium.org303ada72010-10-27 09:33:13 +00008525static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8526 LookupResult* result,
8527 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008528 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008529 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008530 case NORMAL:
8531 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008532 if (value->IsTheHole()) {
8533 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008534 }
8535 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008536 case FIELD:
8537 value =
8538 JSObject::cast(
8539 result->holder())->FastPropertyAt(result->GetFieldIndex());
8540 if (value->IsTheHole()) {
8541 return Heap::undefined_value();
8542 }
8543 return value;
8544 case CONSTANT_FUNCTION:
8545 return result->GetConstantFunction();
8546 case CALLBACKS: {
8547 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008548 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008549 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008550 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008551 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008552 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008553 ASSERT(maybe_value->IsException());
8554 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008555 Top::clear_pending_exception();
8556 if (caught_exception != NULL) {
8557 *caught_exception = true;
8558 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008559 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008560 }
8561 return value;
8562 } else {
8563 return Heap::undefined_value();
8564 }
8565 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008566 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008567 case MAP_TRANSITION:
8568 case CONSTANT_TRANSITION:
8569 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008570 return Heap::undefined_value();
8571 default:
8572 UNREACHABLE();
8573 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008574 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008575 return Heap::undefined_value();
8576}
8577
8578
ager@chromium.org32912102009-01-16 10:38:43 +00008579// Get debugger related details for an object property.
8580// args[0]: object holding property
8581// args[1]: name of the property
8582//
8583// The array returned contains the following information:
8584// 0: Property value
8585// 1: Property details
8586// 2: Property value is exception
8587// 3: Getter function if defined
8588// 4: Setter function if defined
8589// Items 2-4 are only filled if the property has either a getter or a setter
8590// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008591static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008592 HandleScope scope;
8593
8594 ASSERT(args.length() == 2);
8595
8596 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8597 CONVERT_ARG_CHECKED(String, name, 1);
8598
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008599 // Make sure to set the current context to the context before the debugger was
8600 // entered (if the debugger is entered). The reason for switching context here
8601 // is that for some property lookups (accessors and interceptors) callbacks
8602 // into the embedding application can occour, and the embedding application
8603 // could have the assumption that its own global context is the current
8604 // context and not some internal debugger context.
8605 SaveContext save;
8606 if (Debug::InDebugger()) {
8607 Top::set_context(*Debug::debugger_entry()->GetContext());
8608 }
8609
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008610 // Skip the global proxy as it has no properties and always delegates to the
8611 // real global object.
8612 if (obj->IsJSGlobalProxy()) {
8613 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8614 }
8615
8616
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008617 // Check if the name is trivially convertible to an index and get the element
8618 // if so.
8619 uint32_t index;
8620 if (name->AsArrayIndex(&index)) {
8621 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008622 Object* element_or_char;
8623 { MaybeObject* maybe_element_or_char =
8624 Runtime::GetElementOrCharAt(obj, index);
8625 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8626 return maybe_element_or_char;
8627 }
8628 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008629 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008630 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8631 return *Factory::NewJSArrayWithElements(details);
8632 }
8633
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008634 // Find the number of objects making up this.
8635 int length = LocalPrototypeChainLength(*obj);
8636
8637 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008638 Handle<JSObject> jsproto = obj;
8639 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008640 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008641 jsproto->LocalLookup(*name, &result);
8642 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008643 // LookupResult is not GC safe as it holds raw object pointers.
8644 // GC can happen later in this code so put the required fields into
8645 // local variables using handles when required for later use.
8646 PropertyType result_type = result.type();
8647 Handle<Object> result_callback_obj;
8648 if (result_type == CALLBACKS) {
8649 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8650 }
8651 Smi* property_details = result.GetPropertyDetails().AsSmi();
8652 // DebugLookupResultValue can cause GC so details from LookupResult needs
8653 // to be copied to handles before this.
8654 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008655 Object* raw_value;
8656 { MaybeObject* maybe_raw_value =
8657 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8658 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8659 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008660 Handle<Object> value(raw_value);
8661
8662 // If the callback object is a fixed array then it contains JavaScript
8663 // getter and/or setter.
8664 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8665 result_callback_obj->IsFixedArray();
8666 Handle<FixedArray> details =
8667 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8668 details->set(0, *value);
8669 details->set(1, property_details);
8670 if (hasJavaScriptAccessors) {
8671 details->set(2,
8672 caught_exception ? Heap::true_value()
8673 : Heap::false_value());
8674 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8675 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8676 }
8677
8678 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008679 }
8680 if (i < length - 1) {
8681 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8682 }
8683 }
8684
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008685 return Heap::undefined_value();
8686}
8687
8688
lrn@chromium.org303ada72010-10-27 09:33:13 +00008689static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008690 HandleScope scope;
8691
8692 ASSERT(args.length() == 2);
8693
8694 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8695 CONVERT_ARG_CHECKED(String, name, 1);
8696
8697 LookupResult result;
8698 obj->Lookup(*name, &result);
8699 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008700 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008701 }
8702 return Heap::undefined_value();
8703}
8704
8705
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008706// Return the property type calculated from the property details.
8707// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008708static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008709 ASSERT(args.length() == 1);
8710 CONVERT_CHECKED(Smi, details, args[0]);
8711 PropertyType type = PropertyDetails(details).type();
8712 return Smi::FromInt(static_cast<int>(type));
8713}
8714
8715
8716// Return the property attribute calculated from the property details.
8717// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008718static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008719 ASSERT(args.length() == 1);
8720 CONVERT_CHECKED(Smi, details, args[0]);
8721 PropertyAttributes attributes = PropertyDetails(details).attributes();
8722 return Smi::FromInt(static_cast<int>(attributes));
8723}
8724
8725
8726// Return the property insertion index calculated from the property details.
8727// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008728static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008729 ASSERT(args.length() == 1);
8730 CONVERT_CHECKED(Smi, details, args[0]);
8731 int index = PropertyDetails(details).index();
8732 return Smi::FromInt(index);
8733}
8734
8735
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008736// Return property value from named interceptor.
8737// args[0]: object
8738// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008739static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008740 HandleScope scope;
8741 ASSERT(args.length() == 2);
8742 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8743 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8744 CONVERT_ARG_CHECKED(String, name, 1);
8745
8746 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008747 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008748}
8749
8750
8751// Return element value from indexed interceptor.
8752// args[0]: object
8753// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008754static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8755 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008756 HandleScope scope;
8757 ASSERT(args.length() == 2);
8758 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8759 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8760 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8761
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008762 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008763}
8764
8765
lrn@chromium.org303ada72010-10-27 09:33:13 +00008766static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008767 ASSERT(args.length() >= 1);
8768 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008769 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008770 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008771 return Top::Throw(Heap::illegal_execution_state_symbol());
8772 }
8773
8774 return Heap::true_value();
8775}
8776
8777
lrn@chromium.org303ada72010-10-27 09:33:13 +00008778static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779 HandleScope scope;
8780 ASSERT(args.length() == 1);
8781
8782 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008783 Object* result;
8784 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8785 if (!maybe_result->ToObject(&result)) return maybe_result;
8786 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008787
8788 // Count all frames which are relevant to debugging stack trace.
8789 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008790 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008791 if (id == StackFrame::NO_ID) {
8792 // If there is no JavaScript stack frame count is 0.
8793 return Smi::FromInt(0);
8794 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008795 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8796 return Smi::FromInt(n);
8797}
8798
8799
8800static const int kFrameDetailsFrameIdIndex = 0;
8801static const int kFrameDetailsReceiverIndex = 1;
8802static const int kFrameDetailsFunctionIndex = 2;
8803static const int kFrameDetailsArgumentCountIndex = 3;
8804static const int kFrameDetailsLocalCountIndex = 4;
8805static const int kFrameDetailsSourcePositionIndex = 5;
8806static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008807static const int kFrameDetailsAtReturnIndex = 7;
8808static const int kFrameDetailsDebuggerFrameIndex = 8;
8809static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008810
8811// Return an array with frame details
8812// args[0]: number: break id
8813// args[1]: number: frame index
8814//
8815// The array returned contains the following information:
8816// 0: Frame id
8817// 1: Receiver
8818// 2: Function
8819// 3: Argument count
8820// 4: Local count
8821// 5: Source position
8822// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008823// 7: Is at return
8824// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825// Arguments name, value
8826// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008827// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008828static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008829 HandleScope scope;
8830 ASSERT(args.length() == 2);
8831
8832 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008833 Object* check;
8834 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8835 if (!maybe_check->ToObject(&check)) return maybe_check;
8836 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008837 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8838
8839 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008840 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008841 if (id == StackFrame::NO_ID) {
8842 // If there are no JavaScript stack frames return undefined.
8843 return Heap::undefined_value();
8844 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008845 int count = 0;
8846 JavaScriptFrameIterator it(id);
8847 for (; !it.done(); it.Advance()) {
8848 if (count == index) break;
8849 count++;
8850 }
8851 if (it.done()) return Heap::undefined_value();
8852
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008853 bool is_optimized_frame =
8854 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8855
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008856 // Traverse the saved contexts chain to find the active context for the
8857 // selected frame.
8858 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008859 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008860 save = save->prev();
8861 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008862 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008863
8864 // Get the frame id.
8865 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8866
8867 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008868 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008869
8870 // Check for constructor frame.
8871 bool constructor = it.frame()->IsConstructor();
8872
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008873 // Get scope info and read from it for local variable information.
8874 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008875 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008876 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008877
8878 // Get the context.
8879 Handle<Context> context(Context::cast(it.frame()->context()));
8880
8881 // Get the locals names and values into a temporary array.
8882 //
8883 // TODO(1240907): Hide compiler-introduced stack variables
8884 // (e.g. .result)? For users of the debugger, they will probably be
8885 // confusing.
8886 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008888 // Fill in the names of the locals.
8889 for (int i = 0; i < info.NumberOfLocals(); i++) {
8890 locals->set(i * 2, *info.LocalName(i));
8891 }
8892
8893 // Fill in the values of the locals.
8894 for (int i = 0; i < info.NumberOfLocals(); i++) {
8895 if (is_optimized_frame) {
8896 // If we are inspecting an optimized frame use undefined as the
8897 // value for all locals.
8898 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008899 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008900 // for locals in optimized frames.
8901 locals->set(i * 2 + 1, Heap::undefined_value());
8902 } else if (i < info.number_of_stack_slots()) {
8903 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008904 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8905 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008906 // Traverse the context chain to the function context as all local
8907 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008908 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008909 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910 context = Handle<Context>(context->previous());
8911 }
8912 ASSERT(context->is_function_context());
8913 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008914 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915 }
8916 }
8917
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008918 // Check whether this frame is positioned at return. If not top
8919 // frame or if the frame is optimized it cannot be at a return.
8920 bool at_return = false;
8921 if (!is_optimized_frame && index == 0) {
8922 at_return = Debug::IsBreakAtReturn(it.frame());
8923 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008924
8925 // If positioned just before return find the value to be returned and add it
8926 // to the frame information.
8927 Handle<Object> return_value = Factory::undefined_value();
8928 if (at_return) {
8929 StackFrameIterator it2;
8930 Address internal_frame_sp = NULL;
8931 while (!it2.done()) {
8932 if (it2.frame()->is_internal()) {
8933 internal_frame_sp = it2.frame()->sp();
8934 } else {
8935 if (it2.frame()->is_java_script()) {
8936 if (it2.frame()->id() == it.frame()->id()) {
8937 // The internal frame just before the JavaScript frame contains the
8938 // value to return on top. A debug break at return will create an
8939 // internal frame to store the return value (eax/rax/r0) before
8940 // entering the debug break exit frame.
8941 if (internal_frame_sp != NULL) {
8942 return_value =
8943 Handle<Object>(Memory::Object_at(internal_frame_sp));
8944 break;
8945 }
8946 }
8947 }
8948
8949 // Indicate that the previous frame was not an internal frame.
8950 internal_frame_sp = NULL;
8951 }
8952 it2.Advance();
8953 }
8954 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008955
8956 // Now advance to the arguments adapter frame (if any). It contains all
8957 // the provided parameters whereas the function frame always have the number
8958 // of arguments matching the functions parameters. The rest of the
8959 // information (except for what is collected above) is the same.
8960 it.AdvanceToArgumentsFrame();
8961
8962 // Find the number of arguments to fill. At least fill the number of
8963 // parameters for the function and fill more if more parameters are provided.
8964 int argument_count = info.number_of_parameters();
8965 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8966 argument_count = it.frame()->GetProvidedParametersCount();
8967 }
8968
8969 // Calculate the size of the result.
8970 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008971 2 * (argument_count + info.NumberOfLocals()) +
8972 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8974
8975 // Add the frame id.
8976 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8977
8978 // Add the function (same as in function frame).
8979 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8980
8981 // Add the arguments count.
8982 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8983
8984 // Add the locals count
8985 details->set(kFrameDetailsLocalCountIndex,
8986 Smi::FromInt(info.NumberOfLocals()));
8987
8988 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008989 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8991 } else {
8992 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8993 }
8994
8995 // Add the constructor information.
8996 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8997
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008998 // Add the at return information.
8999 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
9000
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001 // Add information on whether this frame is invoked in the debugger context.
9002 details->set(kFrameDetailsDebuggerFrameIndex,
9003 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
9004
9005 // Fill the dynamic part.
9006 int details_index = kFrameDetailsFirstDynamicIndex;
9007
9008 // Add arguments name and value.
9009 for (int i = 0; i < argument_count; i++) {
9010 // Name of the argument.
9011 if (i < info.number_of_parameters()) {
9012 details->set(details_index++, *info.parameter_name(i));
9013 } else {
9014 details->set(details_index++, Heap::undefined_value());
9015 }
9016
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009017 // Parameter value. If we are inspecting an optimized frame, use
9018 // undefined as the value.
9019 //
9020 // TODO(3141533): We should be able to get the actual parameter
9021 // value for optimized frames.
9022 if (!is_optimized_frame &&
9023 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024 details->set(details_index++, it.frame()->GetParameter(i));
9025 } else {
9026 details->set(details_index++, Heap::undefined_value());
9027 }
9028 }
9029
9030 // Add locals name and value from the temporary copy from the function frame.
9031 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9032 details->set(details_index++, locals->get(i));
9033 }
9034
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009035 // Add the value being returned.
9036 if (at_return) {
9037 details->set(details_index++, *return_value);
9038 }
9039
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009040 // Add the receiver (same as in function frame).
9041 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9042 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
9043 Handle<Object> receiver(it.frame()->receiver());
9044 if (!receiver->IsJSObject()) {
9045 // If the receiver is NOT a JSObject we have hit an optimization
9046 // where a value object is not converted into a wrapped JS objects.
9047 // To hide this optimization from the debugger, we wrap the receiver
9048 // by creating correct wrapper object based on the calling frame's
9049 // global context.
9050 it.Advance();
9051 Handle<Context> calling_frames_global_context(
9052 Context::cast(Context::cast(it.frame()->context())->global_context()));
9053 receiver = Factory::ToObject(receiver, calling_frames_global_context);
9054 }
9055 details->set(kFrameDetailsReceiverIndex, *receiver);
9056
9057 ASSERT_EQ(details_size, details_index);
9058 return *Factory::NewJSArrayWithElements(details);
9059}
9060
9061
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009062// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009063static bool CopyContextLocalsToScopeObject(
ager@chromium.orgb5737492010-07-15 09:29:43 +00009064 Handle<SerializedScopeInfo> serialized_scope_info,
9065 ScopeInfo<>& scope_info,
9066 Handle<Context> context,
9067 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009068 // Fill all context locals to the context extension.
9069 for (int i = Context::MIN_CONTEXT_SLOTS;
9070 i < scope_info.number_of_context_slots();
9071 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009072 int context_index = serialized_scope_info->ContextSlotIndex(
9073 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009074
9075 // Don't include the arguments shadow (.arguments) context variable.
9076 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009077 RETURN_IF_EMPTY_HANDLE_VALUE(
9078 SetProperty(scope_object,
9079 scope_info.context_slot_name(i),
9080 Handle<Object>(context->get(context_index)), NONE),
9081 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009082 }
9083 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009084
9085 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009086}
9087
9088
9089// Create a plain JSObject which materializes the local scope for the specified
9090// frame.
9091static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
9092 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009093 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009094 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9095 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009096
9097 // Allocate and initialize a JSObject with all the arguments, stack locals
9098 // heap locals and extension properties of the debugged function.
9099 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
9100
9101 // First fill all parameters.
9102 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009103 RETURN_IF_EMPTY_HANDLE_VALUE(
9104 SetProperty(local_scope,
9105 scope_info.parameter_name(i),
9106 Handle<Object>(frame->GetParameter(i)), NONE),
9107 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009108 }
9109
9110 // Second fill all stack locals.
9111 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009112 RETURN_IF_EMPTY_HANDLE_VALUE(
9113 SetProperty(local_scope,
9114 scope_info.stack_slot_name(i),
9115 Handle<Object>(frame->GetExpression(i)), NONE),
9116 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009117 }
9118
9119 // Third fill all context locals.
9120 Handle<Context> frame_context(Context::cast(frame->context()));
9121 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009122 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9123 function_context, local_scope)) {
9124 return Handle<JSObject>();
9125 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009126
9127 // Finally copy any properties from the function context extension. This will
9128 // be variables introduced by eval.
9129 if (function_context->closure() == *function) {
9130 if (function_context->has_extension() &&
9131 !function_context->IsGlobalContext()) {
9132 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009133 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009134 for (int i = 0; i < keys->length(); i++) {
9135 // Names of variables introduced by eval are strings.
9136 ASSERT(keys->get(i)->IsString());
9137 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009138 RETURN_IF_EMPTY_HANDLE_VALUE(
9139 SetProperty(local_scope, key, GetProperty(ext, key), NONE),
9140 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009141 }
9142 }
9143 }
9144 return local_scope;
9145}
9146
9147
9148// Create a plain JSObject which materializes the closure content for the
9149// context.
9150static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
9151 ASSERT(context->is_function_context());
9152
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009153 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009154 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9155 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009156
9157 // Allocate and initialize a JSObject with all the content of theis function
9158 // closure.
9159 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
9160
9161 // Check whether the arguments shadow object exists.
9162 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00009163 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
9164 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009165 if (arguments_shadow_index >= 0) {
9166 // In this case all the arguments are available in the arguments shadow
9167 // object.
9168 Handle<JSObject> arguments_shadow(
9169 JSObject::cast(context->get(arguments_shadow_index)));
9170 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009171 // We don't expect exception-throwing getters on the arguments shadow.
9172 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009173 RETURN_IF_EMPTY_HANDLE_VALUE(
9174 SetProperty(closure_scope,
9175 scope_info.parameter_name(i),
9176 Handle<Object>(element),
9177 NONE),
9178 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009179 }
9180 }
9181
9182 // Fill all context locals to the context extension.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009183 if (!CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9184 context, closure_scope)) {
9185 return Handle<JSObject>();
9186 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009187
9188 // Finally copy any properties from the function context extension. This will
9189 // be variables introduced by eval.
9190 if (context->has_extension()) {
9191 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009192 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009193 for (int i = 0; i < keys->length(); i++) {
9194 // Names of variables introduced by eval are strings.
9195 ASSERT(keys->get(i)->IsString());
9196 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009197 RETURN_IF_EMPTY_HANDLE_VALUE(
9198 SetProperty(closure_scope, key, GetProperty(ext, key), NONE),
9199 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009200 }
9201 }
9202
9203 return closure_scope;
9204}
9205
9206
9207// Iterate over the actual scopes visible from a stack frame. All scopes are
9208// backed by an actual context except the local scope, which is inserted
9209// "artifically" in the context chain.
9210class ScopeIterator {
9211 public:
9212 enum ScopeType {
9213 ScopeTypeGlobal = 0,
9214 ScopeTypeLocal,
9215 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009216 ScopeTypeClosure,
9217 // Every catch block contains an implicit with block (its parameter is
9218 // a JSContextExtensionObject) that extends current scope with a variable
9219 // holding exception object. Such with blocks are treated as scopes of their
9220 // own type.
9221 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009222 };
9223
9224 explicit ScopeIterator(JavaScriptFrame* frame)
9225 : frame_(frame),
9226 function_(JSFunction::cast(frame->function())),
9227 context_(Context::cast(frame->context())),
9228 local_done_(false),
9229 at_local_(false) {
9230
9231 // Check whether the first scope is actually a local scope.
9232 if (context_->IsGlobalContext()) {
9233 // If there is a stack slot for .result then this local scope has been
9234 // created for evaluating top level code and it is not a real local scope.
9235 // Checking for the existence of .result seems fragile, but the scope info
9236 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009237 int index = function_->shared()->scope_info()->
9238 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009239 at_local_ = index < 0;
9240 } else if (context_->is_function_context()) {
9241 at_local_ = true;
9242 }
9243 }
9244
9245 // More scopes?
9246 bool Done() { return context_.is_null(); }
9247
9248 // Move to the next scope.
9249 void Next() {
9250 // If at a local scope mark the local scope as passed.
9251 if (at_local_) {
9252 at_local_ = false;
9253 local_done_ = true;
9254
9255 // If the current context is not associated with the local scope the
9256 // current context is the next real scope, so don't move to the next
9257 // context in this case.
9258 if (context_->closure() != *function_) {
9259 return;
9260 }
9261 }
9262
9263 // The global scope is always the last in the chain.
9264 if (context_->IsGlobalContext()) {
9265 context_ = Handle<Context>();
9266 return;
9267 }
9268
9269 // Move to the next context.
9270 if (context_->is_function_context()) {
9271 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9272 } else {
9273 context_ = Handle<Context>(context_->previous());
9274 }
9275
9276 // If passing the local scope indicate that the current scope is now the
9277 // local scope.
9278 if (!local_done_ &&
9279 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9280 at_local_ = true;
9281 }
9282 }
9283
9284 // Return the type of the current scope.
9285 int Type() {
9286 if (at_local_) {
9287 return ScopeTypeLocal;
9288 }
9289 if (context_->IsGlobalContext()) {
9290 ASSERT(context_->global()->IsGlobalObject());
9291 return ScopeTypeGlobal;
9292 }
9293 if (context_->is_function_context()) {
9294 return ScopeTypeClosure;
9295 }
9296 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009297 // Current scope is either an explicit with statement or a with statement
9298 // implicitely generated for a catch block.
9299 // If the extension object here is a JSContextExtensionObject then
9300 // current with statement is one frome a catch block otherwise it's a
9301 // regular with statement.
9302 if (context_->extension()->IsJSContextExtensionObject()) {
9303 return ScopeTypeCatch;
9304 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009305 return ScopeTypeWith;
9306 }
9307
9308 // Return the JavaScript object with the content of the current scope.
9309 Handle<JSObject> ScopeObject() {
9310 switch (Type()) {
9311 case ScopeIterator::ScopeTypeGlobal:
9312 return Handle<JSObject>(CurrentContext()->global());
9313 break;
9314 case ScopeIterator::ScopeTypeLocal:
9315 // Materialize the content of the local scope into a JSObject.
9316 return MaterializeLocalScope(frame_);
9317 break;
9318 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009319 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009320 // Return the with object.
9321 return Handle<JSObject>(CurrentContext()->extension());
9322 break;
9323 case ScopeIterator::ScopeTypeClosure:
9324 // Materialize the content of the closure scope into a JSObject.
9325 return MaterializeClosure(CurrentContext());
9326 break;
9327 }
9328 UNREACHABLE();
9329 return Handle<JSObject>();
9330 }
9331
9332 // Return the context for this scope. For the local context there might not
9333 // be an actual context.
9334 Handle<Context> CurrentContext() {
9335 if (at_local_ && context_->closure() != *function_) {
9336 return Handle<Context>();
9337 }
9338 return context_;
9339 }
9340
9341#ifdef DEBUG
9342 // Debug print of the content of the current scope.
9343 void DebugPrint() {
9344 switch (Type()) {
9345 case ScopeIterator::ScopeTypeGlobal:
9346 PrintF("Global:\n");
9347 CurrentContext()->Print();
9348 break;
9349
9350 case ScopeIterator::ScopeTypeLocal: {
9351 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009352 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009353 scope_info.Print();
9354 if (!CurrentContext().is_null()) {
9355 CurrentContext()->Print();
9356 if (CurrentContext()->has_extension()) {
9357 Handle<JSObject> extension =
9358 Handle<JSObject>(CurrentContext()->extension());
9359 if (extension->IsJSContextExtensionObject()) {
9360 extension->Print();
9361 }
9362 }
9363 }
9364 break;
9365 }
9366
9367 case ScopeIterator::ScopeTypeWith: {
9368 PrintF("With:\n");
9369 Handle<JSObject> extension =
9370 Handle<JSObject>(CurrentContext()->extension());
9371 extension->Print();
9372 break;
9373 }
9374
ager@chromium.orga1645e22009-09-09 19:27:10 +00009375 case ScopeIterator::ScopeTypeCatch: {
9376 PrintF("Catch:\n");
9377 Handle<JSObject> extension =
9378 Handle<JSObject>(CurrentContext()->extension());
9379 extension->Print();
9380 break;
9381 }
9382
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009383 case ScopeIterator::ScopeTypeClosure: {
9384 PrintF("Closure:\n");
9385 CurrentContext()->Print();
9386 if (CurrentContext()->has_extension()) {
9387 Handle<JSObject> extension =
9388 Handle<JSObject>(CurrentContext()->extension());
9389 if (extension->IsJSContextExtensionObject()) {
9390 extension->Print();
9391 }
9392 }
9393 break;
9394 }
9395
9396 default:
9397 UNREACHABLE();
9398 }
9399 PrintF("\n");
9400 }
9401#endif
9402
9403 private:
9404 JavaScriptFrame* frame_;
9405 Handle<JSFunction> function_;
9406 Handle<Context> context_;
9407 bool local_done_;
9408 bool at_local_;
9409
9410 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9411};
9412
9413
lrn@chromium.org303ada72010-10-27 09:33:13 +00009414static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009415 HandleScope scope;
9416 ASSERT(args.length() == 2);
9417
9418 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009419 Object* check;
9420 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9421 if (!maybe_check->ToObject(&check)) return maybe_check;
9422 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009423 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9424
9425 // Get the frame where the debugging is performed.
9426 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9427 JavaScriptFrameIterator it(id);
9428 JavaScriptFrame* frame = it.frame();
9429
9430 // Count the visible scopes.
9431 int n = 0;
9432 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9433 n++;
9434 }
9435
9436 return Smi::FromInt(n);
9437}
9438
9439
9440static const int kScopeDetailsTypeIndex = 0;
9441static const int kScopeDetailsObjectIndex = 1;
9442static const int kScopeDetailsSize = 2;
9443
9444// Return an array with scope details
9445// args[0]: number: break id
9446// args[1]: number: frame index
9447// args[2]: number: scope index
9448//
9449// The array returned contains the following information:
9450// 0: Scope type
9451// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009452static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009453 HandleScope scope;
9454 ASSERT(args.length() == 3);
9455
9456 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009457 Object* check;
9458 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9459 if (!maybe_check->ToObject(&check)) return maybe_check;
9460 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009461 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9462 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9463
9464 // Get the frame where the debugging is performed.
9465 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9466 JavaScriptFrameIterator frame_it(id);
9467 JavaScriptFrame* frame = frame_it.frame();
9468
9469 // Find the requested scope.
9470 int n = 0;
9471 ScopeIterator it(frame);
9472 for (; !it.Done() && n < index; it.Next()) {
9473 n++;
9474 }
9475 if (it.Done()) {
9476 return Heap::undefined_value();
9477 }
9478
9479 // Calculate the size of the result.
9480 int details_size = kScopeDetailsSize;
9481 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9482
9483 // Fill in scope details.
9484 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009485 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009486 RETURN_IF_EMPTY_HANDLE(scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009487 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009488
9489 return *Factory::NewJSArrayWithElements(details);
9490}
9491
9492
lrn@chromium.org303ada72010-10-27 09:33:13 +00009493static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009494 HandleScope scope;
9495 ASSERT(args.length() == 0);
9496
9497#ifdef DEBUG
9498 // Print the scopes for the top frame.
9499 StackFrameLocator locator;
9500 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9501 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9502 it.DebugPrint();
9503 }
9504#endif
9505 return Heap::undefined_value();
9506}
9507
9508
lrn@chromium.org303ada72010-10-27 09:33:13 +00009509static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009510 HandleScope scope;
9511 ASSERT(args.length() == 1);
9512
9513 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009514 Object* result;
9515 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9516 if (!maybe_result->ToObject(&result)) return maybe_result;
9517 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009518
9519 // Count all archived V8 threads.
9520 int n = 0;
9521 for (ThreadState* thread = ThreadState::FirstInUse();
9522 thread != NULL;
9523 thread = thread->Next()) {
9524 n++;
9525 }
9526
9527 // Total number of threads is current thread and archived threads.
9528 return Smi::FromInt(n + 1);
9529}
9530
9531
9532static const int kThreadDetailsCurrentThreadIndex = 0;
9533static const int kThreadDetailsThreadIdIndex = 1;
9534static const int kThreadDetailsSize = 2;
9535
9536// Return an array with thread details
9537// args[0]: number: break id
9538// args[1]: number: thread index
9539//
9540// The array returned contains the following information:
9541// 0: Is current thread?
9542// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009543static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009544 HandleScope scope;
9545 ASSERT(args.length() == 2);
9546
9547 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009548 Object* check;
9549 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9550 if (!maybe_check->ToObject(&check)) return maybe_check;
9551 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009552 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9553
9554 // Allocate array for result.
9555 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9556
9557 // Thread index 0 is current thread.
9558 if (index == 0) {
9559 // Fill the details.
9560 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9561 details->set(kThreadDetailsThreadIdIndex,
9562 Smi::FromInt(ThreadManager::CurrentId()));
9563 } else {
9564 // Find the thread with the requested index.
9565 int n = 1;
9566 ThreadState* thread = ThreadState::FirstInUse();
9567 while (index != n && thread != NULL) {
9568 thread = thread->Next();
9569 n++;
9570 }
9571 if (thread == NULL) {
9572 return Heap::undefined_value();
9573 }
9574
9575 // Fill the details.
9576 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9577 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9578 }
9579
9580 // Convert to JS array and return.
9581 return *Factory::NewJSArrayWithElements(details);
9582}
9583
9584
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009585// Sets the disable break state
9586// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009587static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009588 HandleScope scope;
9589 ASSERT(args.length() == 1);
9590 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9591 Debug::set_disable_break(disable_break);
9592 return Heap::undefined_value();
9593}
9594
9595
lrn@chromium.org303ada72010-10-27 09:33:13 +00009596static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009597 HandleScope scope;
9598 ASSERT(args.length() == 1);
9599
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009600 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9601 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009602 // Find the number of break points
9603 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9604 if (break_locations->IsUndefined()) return Heap::undefined_value();
9605 // Return array as JS array
9606 return *Factory::NewJSArrayWithElements(
9607 Handle<FixedArray>::cast(break_locations));
9608}
9609
9610
9611// Set a break point in a function
9612// args[0]: function
9613// args[1]: number: break source position (within the function source)
9614// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009615static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009616 HandleScope scope;
9617 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009618 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9619 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009620 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9621 RUNTIME_ASSERT(source_position >= 0);
9622 Handle<Object> break_point_object_arg = args.at<Object>(2);
9623
9624 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009625 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009626
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009627 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009628}
9629
9630
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009631Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9632 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009633 // Iterate the heap looking for SharedFunctionInfo generated from the
9634 // script. The inner most SharedFunctionInfo containing the source position
9635 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009636 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009637 // which is found is not compiled it is compiled and the heap is iterated
9638 // again as the compilation might create inner functions from the newly
9639 // compiled function and the actual requested break point might be in one of
9640 // these functions.
9641 bool done = false;
9642 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009643 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009644 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009645 while (!done) {
9646 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009647 for (HeapObject* obj = iterator.next();
9648 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009649 if (obj->IsSharedFunctionInfo()) {
9650 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9651 if (shared->script() == *script) {
9652 // If the SharedFunctionInfo found has the requested script data and
9653 // contains the source position it is a candidate.
9654 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009655 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009656 start_position = shared->start_position();
9657 }
9658 if (start_position <= position &&
9659 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009660 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009661 // candidate this is the new candidate.
9662 if (target.is_null()) {
9663 target_start_position = start_position;
9664 target = shared;
9665 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009666 if (target_start_position == start_position &&
9667 shared->end_position() == target->end_position()) {
9668 // If a top-level function contain only one function
9669 // declartion the source for the top-level and the function is
9670 // the same. In that case prefer the non top-level function.
9671 if (!shared->is_toplevel()) {
9672 target_start_position = start_position;
9673 target = shared;
9674 }
9675 } else if (target_start_position <= start_position &&
9676 shared->end_position() <= target->end_position()) {
9677 // This containment check includes equality as a function inside
9678 // a top-level function can share either start or end position
9679 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009680 target_start_position = start_position;
9681 target = shared;
9682 }
9683 }
9684 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009685 }
9686 }
9687 }
9688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009689 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009690 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691 }
9692
9693 // If the candidate found is compiled we are done. NOTE: when lazy
9694 // compilation of inner functions is introduced some additional checking
9695 // needs to be done here to compile inner functions.
9696 done = target->is_compiled();
9697 if (!done) {
9698 // If the candidate is not compiled compile it to reveal any inner
9699 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009700 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009701 }
9702 }
9703
9704 return *target;
9705}
9706
9707
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009708// Changes the state of a break point in a script and returns source position
9709// where break point was set. NOTE: Regarding performance see the NOTE for
9710// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009711// args[0]: script to set break point in
9712// args[1]: number: break source position (within the script source)
9713// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009714static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009715 HandleScope scope;
9716 ASSERT(args.length() == 3);
9717 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9718 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9719 RUNTIME_ASSERT(source_position >= 0);
9720 Handle<Object> break_point_object_arg = args.at<Object>(2);
9721
9722 // Get the script from the script wrapper.
9723 RUNTIME_ASSERT(wrapper->value()->IsScript());
9724 Handle<Script> script(Script::cast(wrapper->value()));
9725
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009726 Object* result = Runtime::FindSharedFunctionInfoInScript(
9727 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009728 if (!result->IsUndefined()) {
9729 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9730 // Find position within function. The script position might be before the
9731 // source position of the first function.
9732 int position;
9733 if (shared->start_position() > source_position) {
9734 position = 0;
9735 } else {
9736 position = source_position - shared->start_position();
9737 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009738 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9739 position += shared->start_position();
9740 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009741 }
9742 return Heap::undefined_value();
9743}
9744
9745
9746// Clear a break point
9747// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009748static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009749 HandleScope scope;
9750 ASSERT(args.length() == 1);
9751 Handle<Object> break_point_object_arg = args.at<Object>(0);
9752
9753 // Clear break point.
9754 Debug::ClearBreakPoint(break_point_object_arg);
9755
9756 return Heap::undefined_value();
9757}
9758
9759
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009760// Change the state of break on exceptions.
9761// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9762// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009763static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009764 HandleScope scope;
9765 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009766 RUNTIME_ASSERT(args[0]->IsNumber());
9767 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009768
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009769 // If the number doesn't match an enum value, the ChangeBreakOnException
9770 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009771 ExceptionBreakType type =
9772 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009773 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009774 Debug::ChangeBreakOnException(type, enable);
9775 return Heap::undefined_value();
9776}
9777
9778
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009779// Returns the state of break on exceptions
9780// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009781static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009782 HandleScope scope;
9783 ASSERT(args.length() == 1);
9784 RUNTIME_ASSERT(args[0]->IsNumber());
9785
9786 ExceptionBreakType type =
9787 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9788 bool result = Debug::IsBreakOnException(type);
9789 return Smi::FromInt(result);
9790}
9791
9792
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009793// Prepare for stepping
9794// args[0]: break id for checking execution state
9795// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009796// args[2]: number of times to perform the step, for step out it is the number
9797// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009798static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009799 HandleScope scope;
9800 ASSERT(args.length() == 3);
9801 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009802 Object* check;
9803 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9804 if (!maybe_check->ToObject(&check)) return maybe_check;
9805 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009806 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9807 return Top::Throw(Heap::illegal_argument_symbol());
9808 }
9809
9810 // Get the step action and check validity.
9811 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9812 if (step_action != StepIn &&
9813 step_action != StepNext &&
9814 step_action != StepOut &&
9815 step_action != StepInMin &&
9816 step_action != StepMin) {
9817 return Top::Throw(Heap::illegal_argument_symbol());
9818 }
9819
9820 // Get the number of steps.
9821 int step_count = NumberToInt32(args[2]);
9822 if (step_count < 1) {
9823 return Top::Throw(Heap::illegal_argument_symbol());
9824 }
9825
ager@chromium.orga1645e22009-09-09 19:27:10 +00009826 // Clear all current stepping setup.
9827 Debug::ClearStepping();
9828
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009829 // Prepare step.
9830 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9831 return Heap::undefined_value();
9832}
9833
9834
9835// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009836static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009837 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009838 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009839 Debug::ClearStepping();
9840 return Heap::undefined_value();
9841}
9842
9843
9844// Creates a copy of the with context chain. The copy of the context chain is
9845// is linked to the function context supplied.
9846static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9847 Handle<Context> function_context) {
9848 // At the bottom of the chain. Return the function context to link to.
9849 if (context_chain->is_function_context()) {
9850 return function_context;
9851 }
9852
9853 // Recursively copy the with contexts.
9854 Handle<Context> previous(context_chain->previous());
9855 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009856 Handle<Context> context = CopyWithContextChain(function_context, previous);
9857 return Factory::NewWithContext(context,
9858 extension,
9859 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009860}
9861
9862
9863// Helper function to find or create the arguments object for
9864// Runtime_DebugEvaluate.
9865static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9866 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009867 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009868 const ScopeInfo<>* sinfo,
9869 Handle<Context> function_context) {
9870 // Try to find the value of 'arguments' to pass as parameter. If it is not
9871 // found (that is the debugged function does not reference 'arguments' and
9872 // does not support eval) then create an 'arguments' object.
9873 int index;
9874 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009875 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009876 if (index != -1) {
9877 return Handle<Object>(frame->GetExpression(index));
9878 }
9879 }
9880
9881 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009882 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009883 if (index != -1) {
9884 return Handle<Object>(function_context->get(index));
9885 }
9886 }
9887
9888 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009889 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9890 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009891
9892 AssertNoAllocation no_gc;
9893 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009894 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009895 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009896 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009897 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009898 return arguments;
9899}
9900
9901
9902// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009903// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009904// extension part has all the parameters and locals of the function on the
9905// stack frame. A function which calls eval with the code to evaluate is then
9906// compiled in this context and called in this context. As this context
9907// replaces the context of the function on the stack frame a new (empty)
9908// function is created as well to be used as the closure for the context.
9909// This function and the context acts as replacements for the function on the
9910// stack frame presenting the same view of the values of parameters and
9911// local variables as if the piece of JavaScript was evaluated at the point
9912// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009913static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009914 HandleScope scope;
9915
9916 // Check the execution state and decode arguments frame and source to be
9917 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009918 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009919 Object* check_result;
9920 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9921 if (!maybe_check_result->ToObject(&check_result)) {
9922 return maybe_check_result;
9923 }
9924 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009925 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9926 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009927 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009928 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009929
9930 // Handle the processing of break.
9931 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932
9933 // Get the frame where the debugging is performed.
9934 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9935 JavaScriptFrameIterator it(id);
9936 JavaScriptFrame* frame = it.frame();
9937 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009938 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009939 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009940
9941 // Traverse the saved contexts chain to find the active context for the
9942 // selected frame.
9943 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009944 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009945 save = save->prev();
9946 }
9947 ASSERT(save != NULL);
9948 SaveContext savex;
9949 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009950
9951 // Create the (empty) function replacing the function on the stack frame for
9952 // the purpose of evaluating in the context created below. It is important
9953 // that this function does not describe any parameters and local variables
9954 // in the context. If it does then this will cause problems with the lookup
9955 // in Context::Lookup, where context slots for parameters and local variables
9956 // are looked at before the extension object.
9957 Handle<JSFunction> go_between =
9958 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9959 go_between->set_context(function->context());
9960#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009961 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9963 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9964#endif
9965
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009966 // Materialize the content of the local scope into a JSObject.
9967 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009968 RETURN_IF_EMPTY_HANDLE(local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009969
9970 // Allocate a new context for the debug evaluation and set the extension
9971 // object build.
9972 Handle<Context> context =
9973 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009974 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009975 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009976 Handle<Context> frame_context(Context::cast(frame->context()));
9977 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009978 context = CopyWithContextChain(frame_context, context);
9979
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009980 if (additional_context->IsJSObject()) {
9981 context = Factory::NewWithContext(context,
9982 Handle<JSObject>::cast(additional_context), false);
9983 }
9984
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 // Wrap the evaluation statement in a new function compiled in the newly
9986 // created context. The function has one parameter which has to be called
9987 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009988 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989 // function(arguments,__source__) {return eval(__source__);}
9990 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009991 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009992 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 Handle<String> function_source =
9994 Factory::NewStringFromAscii(Vector<const char>(source_str,
9995 source_str_length));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009996
9997 // Currently, the eval code will be executed in non-strict mode,
9998 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009999 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010000 Compiler::CompileEval(function_source,
10001 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010002 context->IsGlobalContext(),
10003 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010004 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010005 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010006 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010007
10008 // Invoke the result of the compilation to get the evaluation function.
10009 bool has_pending_exception;
10010 Handle<Object> receiver(frame->receiver());
10011 Handle<Object> evaluation_function =
10012 Execution::Call(compiled_function, receiver, 0, NULL,
10013 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010014 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010015
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010016 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
10017 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018
10019 // Invoke the evaluation function and return the result.
10020 const int argc = 2;
10021 Object** argv[argc] = { arguments.location(),
10022 Handle<Object>::cast(source).location() };
10023 Handle<Object> result =
10024 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10025 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010026 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010027
10028 // Skip the global proxy as it has no properties and always delegates to the
10029 // real global object.
10030 if (result->IsJSGlobalProxy()) {
10031 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10032 }
10033
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010034 return *result;
10035}
10036
10037
lrn@chromium.org303ada72010-10-27 09:33:13 +000010038static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010039 HandleScope scope;
10040
10041 // Check the execution state and decode arguments frame and source to be
10042 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010043 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010044 Object* check_result;
10045 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
10046 if (!maybe_check_result->ToObject(&check_result)) {
10047 return maybe_check_result;
10048 }
10049 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010050 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010051 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010052 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010053
10054 // Handle the processing of break.
10055 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010056
10057 // Enter the top context from before the debugger was invoked.
10058 SaveContext save;
10059 SaveContext* top = &save;
10060 while (top != NULL && *top->context() == *Debug::debug_context()) {
10061 top = top->prev();
10062 }
10063 if (top != NULL) {
10064 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010065 }
10066
10067 // Get the global context now set to the top context from before the
10068 // debugger was invoked.
10069 Handle<Context> context = Top::global_context();
10070
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010071 bool is_global = true;
10072
10073 if (additional_context->IsJSObject()) {
10074 // Create a function context first, than put 'with' context on top of it.
10075 Handle<JSFunction> go_between = Factory::NewFunction(
10076 Factory::empty_string(), Factory::undefined_value());
10077 go_between->set_context(*context);
10078 context =
10079 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
10080 context->set_extension(JSObject::cast(*additional_context));
10081 is_global = false;
10082 }
10083
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010085 // Currently, the eval code will be executed in non-strict mode,
10086 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010087 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010088 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010089 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010090 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010091 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
10092 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010093
10094 // Invoke the result of the compilation to get the evaluation function.
10095 bool has_pending_exception;
10096 Handle<Object> receiver = Top::global();
10097 Handle<Object> result =
10098 Execution::Call(compiled_function, receiver, 0, NULL,
10099 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010100 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010101 return *result;
10102}
10103
10104
lrn@chromium.org303ada72010-10-27 09:33:13 +000010105static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010106 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +000010107 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010109 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010110 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010111
10112 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010113 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010114 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10115 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10116 // because using
10117 // instances->set(i, *GetScriptWrapper(script))
10118 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10119 // already have deferenced the instances handle.
10120 Handle<JSValue> wrapper = GetScriptWrapper(script);
10121 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010122 }
10123
10124 // Return result as a JS array.
10125 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
10126 Handle<JSArray>::cast(result)->SetContent(*instances);
10127 return *result;
10128}
10129
10130
10131// Helper function used by Runtime_DebugReferencedBy below.
10132static int DebugReferencedBy(JSObject* target,
10133 Object* instance_filter, int max_references,
10134 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010135 JSFunction* arguments_function) {
10136 NoHandleAllocation ha;
10137 AssertNoAllocation no_alloc;
10138
10139 // Iterate the heap.
10140 int count = 0;
10141 JSObject* last = NULL;
10142 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010143 HeapObject* heap_obj = NULL;
10144 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010145 (max_references == 0 || count < max_references)) {
10146 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010147 if (heap_obj->IsJSObject()) {
10148 // Skip context extension objects and argument arrays as these are
10149 // checked in the context of functions using them.
10150 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010151 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152 obj->map()->constructor() == arguments_function) {
10153 continue;
10154 }
10155
10156 // Check if the JS object has a reference to the object looked for.
10157 if (obj->ReferencesObject(target)) {
10158 // Check instance filter if supplied. This is normally used to avoid
10159 // references from mirror objects (see Runtime_IsInPrototypeChain).
10160 if (!instance_filter->IsUndefined()) {
10161 Object* V = obj;
10162 while (true) {
10163 Object* prototype = V->GetPrototype();
10164 if (prototype->IsNull()) {
10165 break;
10166 }
10167 if (instance_filter == prototype) {
10168 obj = NULL; // Don't add this object.
10169 break;
10170 }
10171 V = prototype;
10172 }
10173 }
10174
10175 if (obj != NULL) {
10176 // Valid reference found add to instance array if supplied an update
10177 // count.
10178 if (instances != NULL && count < instances_size) {
10179 instances->set(count, obj);
10180 }
10181 last = obj;
10182 count++;
10183 }
10184 }
10185 }
10186 }
10187
10188 // Check for circular reference only. This can happen when the object is only
10189 // referenced from mirrors and has a circular reference in which case the
10190 // object is not really alive and would have been garbage collected if not
10191 // referenced from the mirror.
10192 if (count == 1 && last == target) {
10193 count = 0;
10194 }
10195
10196 // Return the number of referencing objects found.
10197 return count;
10198}
10199
10200
10201// Scan the heap for objects with direct references to an object
10202// args[0]: the object to find references to
10203// args[1]: constructor function for instances to exclude (Mirror)
10204// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010205static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010206 ASSERT(args.length() == 3);
10207
10208 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010209 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010210
10211 // Check parameters.
10212 CONVERT_CHECKED(JSObject, target, args[0]);
10213 Object* instance_filter = args[1];
10214 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10215 instance_filter->IsJSObject());
10216 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10217 RUNTIME_ASSERT(max_references >= 0);
10218
10219 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010220 JSObject* arguments_boilerplate =
10221 Top::context()->global_context()->arguments_boilerplate();
10222 JSFunction* arguments_function =
10223 JSFunction::cast(arguments_boilerplate->map()->constructor());
10224
10225 // Get the number of referencing objects.
10226 int count;
10227 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010228 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010229
10230 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010231 Object* object;
10232 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10233 if (!maybe_object->ToObject(&object)) return maybe_object;
10234 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010235 FixedArray* instances = FixedArray::cast(object);
10236
10237 // Fill the referencing objects.
10238 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010239 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240
10241 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010242 Object* result;
10243 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10244 Top::context()->global_context()->array_function());
10245 if (!maybe_result->ToObject(&result)) return maybe_result;
10246 }
10247 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248 return result;
10249}
10250
10251
10252// Helper function used by Runtime_DebugConstructedBy below.
10253static int DebugConstructedBy(JSFunction* constructor, int max_references,
10254 FixedArray* instances, int instances_size) {
10255 AssertNoAllocation no_alloc;
10256
10257 // Iterate the heap.
10258 int count = 0;
10259 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010260 HeapObject* heap_obj = NULL;
10261 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262 (max_references == 0 || count < max_references)) {
10263 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264 if (heap_obj->IsJSObject()) {
10265 JSObject* obj = JSObject::cast(heap_obj);
10266 if (obj->map()->constructor() == constructor) {
10267 // Valid reference found add to instance array if supplied an update
10268 // count.
10269 if (instances != NULL && count < instances_size) {
10270 instances->set(count, obj);
10271 }
10272 count++;
10273 }
10274 }
10275 }
10276
10277 // Return the number of referencing objects found.
10278 return count;
10279}
10280
10281
10282// Scan the heap for objects constructed by a specific function.
10283// args[0]: the constructor to find instances of
10284// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010285static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 ASSERT(args.length() == 2);
10287
10288 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010289 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290
10291 // Check parameters.
10292 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10293 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10294 RUNTIME_ASSERT(max_references >= 0);
10295
10296 // Get the number of referencing objects.
10297 int count;
10298 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10299
10300 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010301 Object* object;
10302 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10303 if (!maybe_object->ToObject(&object)) return maybe_object;
10304 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010305 FixedArray* instances = FixedArray::cast(object);
10306
10307 // Fill the referencing objects.
10308 count = DebugConstructedBy(constructor, max_references, instances, count);
10309
10310 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010311 Object* result;
10312 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10313 Top::context()->global_context()->array_function());
10314 if (!maybe_result->ToObject(&result)) return maybe_result;
10315 }
10316 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317 return result;
10318}
10319
10320
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010321// Find the effective prototype object as returned by __proto__.
10322// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010323static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324 ASSERT(args.length() == 1);
10325
10326 CONVERT_CHECKED(JSObject, obj, args[0]);
10327
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010328 // Use the __proto__ accessor.
10329 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010330}
10331
10332
lrn@chromium.org303ada72010-10-27 09:33:13 +000010333static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010334 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335 CPU::DebugBreak();
10336 return Heap::undefined_value();
10337}
10338
10339
lrn@chromium.org303ada72010-10-27 09:33:13 +000010340static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010341#ifdef DEBUG
10342 HandleScope scope;
10343 ASSERT(args.length() == 1);
10344 // Get the function and make sure it is compiled.
10345 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010346 Handle<SharedFunctionInfo> shared(func->shared());
10347 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010348 return Failure::Exception();
10349 }
10350 func->code()->PrintLn();
10351#endif // DEBUG
10352 return Heap::undefined_value();
10353}
ager@chromium.org9085a012009-05-11 19:22:57 +000010354
10355
lrn@chromium.org303ada72010-10-27 09:33:13 +000010356static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010357#ifdef DEBUG
10358 HandleScope scope;
10359 ASSERT(args.length() == 1);
10360 // Get the function and make sure it is compiled.
10361 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010362 Handle<SharedFunctionInfo> shared(func->shared());
10363 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010364 return Failure::Exception();
10365 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010366 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010367#endif // DEBUG
10368 return Heap::undefined_value();
10369}
10370
10371
lrn@chromium.org303ada72010-10-27 09:33:13 +000010372static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010373 NoHandleAllocation ha;
10374 ASSERT(args.length() == 1);
10375
10376 CONVERT_CHECKED(JSFunction, f, args[0]);
10377 return f->shared()->inferred_name();
10378}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010379
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010380
10381static int FindSharedFunctionInfosForScript(Script* script,
10382 FixedArray* buffer) {
10383 AssertNoAllocation no_allocations;
10384
10385 int counter = 0;
10386 int buffer_size = buffer->length();
10387 HeapIterator iterator;
10388 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10389 ASSERT(obj != NULL);
10390 if (!obj->IsSharedFunctionInfo()) {
10391 continue;
10392 }
10393 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10394 if (shared->script() != script) {
10395 continue;
10396 }
10397 if (counter < buffer_size) {
10398 buffer->set(counter, shared);
10399 }
10400 counter++;
10401 }
10402 return counter;
10403}
10404
10405// For a script finds all SharedFunctionInfo's in the heap that points
10406// to this script. Returns JSArray of SharedFunctionInfo wrapped
10407// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010408static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010409 Arguments args) {
10410 ASSERT(args.length() == 1);
10411 HandleScope scope;
10412 CONVERT_CHECKED(JSValue, script_value, args[0]);
10413
10414 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10415
10416 const int kBufferSize = 32;
10417
10418 Handle<FixedArray> array;
10419 array = Factory::NewFixedArray(kBufferSize);
10420 int number = FindSharedFunctionInfosForScript(*script, *array);
10421 if (number > kBufferSize) {
10422 array = Factory::NewFixedArray(number);
10423 FindSharedFunctionInfosForScript(*script, *array);
10424 }
10425
10426 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10427 result->set_length(Smi::FromInt(number));
10428
10429 LiveEdit::WrapSharedFunctionInfos(result);
10430
10431 return *result;
10432}
10433
10434// For a script calculates compilation information about all its functions.
10435// The script source is explicitly specified by the second argument.
10436// The source of the actual script is not used, however it is important that
10437// all generated code keeps references to this particular instance of script.
10438// Returns a JSArray of compilation infos. The array is ordered so that
10439// each function with all its descendant is always stored in a continues range
10440// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010441static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010442 ASSERT(args.length() == 2);
10443 HandleScope scope;
10444 CONVERT_CHECKED(JSValue, script, args[0]);
10445 CONVERT_ARG_CHECKED(String, source, 1);
10446 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10447
10448 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10449
10450 if (Top::has_pending_exception()) {
10451 return Failure::Exception();
10452 }
10453
10454 return result;
10455}
10456
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010457// Changes the source of the script to a new_source.
10458// If old_script_name is provided (i.e. is a String), also creates a copy of
10459// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010460static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010461 ASSERT(args.length() == 3);
10462 HandleScope scope;
10463 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10464 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010465 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010466
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010467 CONVERT_CHECKED(Script, original_script_pointer,
10468 original_script_value->value());
10469 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010470
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010471 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10472 new_source,
10473 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010474
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010475 if (old_script->IsScript()) {
10476 Handle<Script> script_handle(Script::cast(old_script));
10477 return *(GetScriptWrapper(script_handle));
10478 } else {
10479 return Heap::null_value();
10480 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010481}
10482
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010483
10484static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10485 ASSERT(args.length() == 1);
10486 HandleScope scope;
10487 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10488 return LiveEdit::FunctionSourceUpdated(shared_info);
10489}
10490
10491
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010492// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010493static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010494 ASSERT(args.length() == 2);
10495 HandleScope scope;
10496 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10497 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10498
ager@chromium.orgac091b72010-05-05 07:34:42 +000010499 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010500}
10501
10502// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010503static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010504 ASSERT(args.length() == 2);
10505 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010506 Handle<Object> function_object(args[0]);
10507 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010508
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010509 if (function_object->IsJSValue()) {
10510 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10511 if (script_object->IsJSValue()) {
10512 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10513 script_object = Handle<Object>(script);
10514 }
10515
10516 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10517 } else {
10518 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10519 // and we check it in this function.
10520 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010521
10522 return Heap::undefined_value();
10523}
10524
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010525
10526// In a code of a parent function replaces original function as embedded object
10527// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010528static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010529 ASSERT(args.length() == 3);
10530 HandleScope scope;
10531
10532 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10533 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10534 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10535
10536 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10537 subst_wrapper);
10538
10539 return Heap::undefined_value();
10540}
10541
10542
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010543// Updates positions of a shared function info (first parameter) according
10544// to script source change. Text change is described in second parameter as
10545// array of groups of 3 numbers:
10546// (change_begin, change_end, change_end_new_position).
10547// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010548static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010549 ASSERT(args.length() == 2);
10550 HandleScope scope;
10551 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10552 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10553
ager@chromium.orgac091b72010-05-05 07:34:42 +000010554 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010555}
10556
10557
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010558// For array of SharedFunctionInfo's (each wrapped in JSValue)
10559// checks that none of them have activations on stacks (of any thread).
10560// Returns array of the same length with corresponding results of
10561// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010562static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010563 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010564 HandleScope scope;
10565 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010566 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010567
ager@chromium.org357bf652010-04-12 11:30:10 +000010568 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010569}
10570
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010571// Compares 2 strings line-by-line, then token-wise and returns diff in form
10572// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10573// of diff chunks.
10574static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010575 ASSERT(args.length() == 2);
10576 HandleScope scope;
10577 CONVERT_ARG_CHECKED(String, s1, 0);
10578 CONVERT_ARG_CHECKED(String, s2, 1);
10579
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010580 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010581}
10582
10583
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010584
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010585// A testing entry. Returns statement position which is the closest to
10586// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010587static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010588 ASSERT(args.length() == 2);
10589 HandleScope scope;
10590 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10591 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10592
10593 Handle<Code> code(function->code());
10594
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010595 if (code->kind() != Code::FUNCTION &&
10596 code->kind() != Code::OPTIMIZED_FUNCTION) {
10597 return Heap::undefined_value();
10598 }
10599
10600 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010601 int closest_pc = 0;
10602 int distance = kMaxInt;
10603 while (!it.done()) {
10604 int statement_position = static_cast<int>(it.rinfo()->data());
10605 // Check if this break point is closer that what was previously found.
10606 if (source_position <= statement_position &&
10607 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010608 closest_pc =
10609 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010610 distance = statement_position - source_position;
10611 // Check whether we can't get any closer.
10612 if (distance == 0) break;
10613 }
10614 it.next();
10615 }
10616
10617 return Smi::FromInt(closest_pc);
10618}
10619
10620
ager@chromium.org357bf652010-04-12 11:30:10 +000010621// Calls specified function with or without entering the debugger.
10622// This is used in unit tests to run code as if debugger is entered or simply
10623// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010624static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010625 ASSERT(args.length() == 2);
10626 HandleScope scope;
10627 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10628 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10629
10630 Handle<Object> result;
10631 bool pending_exception;
10632 {
10633 if (without_debugger) {
10634 result = Execution::Call(function, Top::global(), 0, NULL,
10635 &pending_exception);
10636 } else {
10637 EnterDebugger enter_debugger;
10638 result = Execution::Call(function, Top::global(), 0, NULL,
10639 &pending_exception);
10640 }
10641 }
10642 if (!pending_exception) {
10643 return *result;
10644 } else {
10645 return Failure::Exception();
10646 }
10647}
10648
10649
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010650// Sets a v8 flag.
10651static MaybeObject* Runtime_SetFlags(Arguments args) {
10652 CONVERT_CHECKED(String, arg, args[0]);
10653 SmartPointer<char> flags =
10654 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10655 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10656 return Heap::undefined_value();
10657}
10658
10659
10660// Performs a GC.
10661// Presently, it only does a full GC.
10662static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10663 Heap::CollectAllGarbage(true);
10664 return Heap::undefined_value();
10665}
10666
10667
10668// Gets the current heap usage.
10669static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10670 int usage = static_cast<int>(Heap::SizeOfObjects());
10671 if (!Smi::IsValid(usage)) {
10672 return *Factory::NewNumberFromInt(usage);
10673 }
10674 return Smi::FromInt(usage);
10675}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010676#endif // ENABLE_DEBUGGER_SUPPORT
10677
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010678
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010679#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000010680static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010681 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010682 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010683
10684 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010685 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10686 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010687 return Heap::undefined_value();
10688}
10689
10690
lrn@chromium.org303ada72010-10-27 09:33:13 +000010691static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010692 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010693 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010694
10695 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010696 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10697 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010698 return Heap::undefined_value();
10699}
10700
10701#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010702
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010703// Finds the script object from the script data. NOTE: This operation uses
10704// heap traversal to find the function generated for the source position
10705// for the requested break point. For lazily compiled functions several heap
10706// traversals might be required rendering this operation as a rather slow
10707// operation. However for setting break points which is normally done through
10708// some kind of user interaction the performance is not crucial.
10709static Handle<Object> Runtime_GetScriptFromScriptName(
10710 Handle<String> script_name) {
10711 // Scan the heap for Script objects to find the script with the requested
10712 // script data.
10713 Handle<Script> script;
10714 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010715 HeapObject* obj = NULL;
10716 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010717 // If a script is found check if it has the script data requested.
10718 if (obj->IsScript()) {
10719 if (Script::cast(obj)->name()->IsString()) {
10720 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10721 script = Handle<Script>(Script::cast(obj));
10722 }
10723 }
10724 }
10725 }
10726
10727 // If no script with the requested script data is found return undefined.
10728 if (script.is_null()) return Factory::undefined_value();
10729
10730 // Return the script found.
10731 return GetScriptWrapper(script);
10732}
10733
10734
10735// Get the script object from script data. NOTE: Regarding performance
10736// see the NOTE for GetScriptFromScriptData.
10737// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010738static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010739 HandleScope scope;
10740
10741 ASSERT(args.length() == 1);
10742
10743 CONVERT_CHECKED(String, script_name, args[0]);
10744
10745 // Find the requested script.
10746 Handle<Object> result =
10747 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10748 return *result;
10749}
10750
10751
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010752// Determines whether the given stack frame should be displayed in
10753// a stack trace. The caller is the error constructor that asked
10754// for the stack trace to be collected. The first time a construct
10755// call to this function is encountered it is skipped. The seen_caller
10756// in/out parameter is used to remember if the caller has been seen
10757// yet.
10758static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10759 bool* seen_caller) {
10760 // Only display JS frames.
10761 if (!raw_frame->is_java_script())
10762 return false;
10763 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10764 Object* raw_fun = frame->function();
10765 // Not sure when this can happen but skip it just in case.
10766 if (!raw_fun->IsJSFunction())
10767 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010768 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010769 *seen_caller = true;
10770 return false;
10771 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010772 // Skip all frames until we've seen the caller. Also, skip the most
10773 // obvious builtin calls. Some builtin calls (such as Number.ADD
10774 // which is invoked using 'call') are very difficult to recognize
10775 // so we're leaving them in for now.
10776 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010777}
10778
10779
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010780// Collect the raw data for a stack trace. Returns an array of 4
10781// element segments each containing a receiver, function, code and
10782// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010783static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010784 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010785 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010786 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10787
10788 HandleScope scope;
10789
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010790 limit = Max(limit, 0); // Ensure that limit is not negative.
10791 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010792 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010793
10794 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010795 // If the caller parameter is a function we skip frames until we're
10796 // under it before starting to collect.
10797 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010798 int cursor = 0;
10799 int frames_seen = 0;
10800 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010801 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010802 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010803 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010804 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010805 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10806 frame->Summarize(&frames);
10807 for (int i = frames.length() - 1; i >= 0; i--) {
10808 Handle<Object> recv = frames[i].receiver();
10809 Handle<JSFunction> fun = frames[i].function();
10810 Handle<Code> code = frames[i].code();
10811 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10812 FixedArray* elements = FixedArray::cast(result->elements());
10813 if (cursor + 3 < elements->length()) {
10814 elements->set(cursor++, *recv);
10815 elements->set(cursor++, *fun);
10816 elements->set(cursor++, *code);
10817 elements->set(cursor++, *offset);
10818 } else {
10819 SetElement(result, cursor++, recv);
10820 SetElement(result, cursor++, fun);
10821 SetElement(result, cursor++, code);
10822 SetElement(result, cursor++, offset);
10823 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010824 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010825 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010826 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010827 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010828
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010829 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010830 return *result;
10831}
10832
10833
ager@chromium.org3811b432009-10-28 14:53:37 +000010834// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010835static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010836 ASSERT_EQ(args.length(), 0);
10837
10838 NoHandleAllocation ha;
10839
10840 const char* version_string = v8::V8::GetVersion();
10841
10842 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10843}
10844
10845
lrn@chromium.org303ada72010-10-27 09:33:13 +000010846static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010847 ASSERT(args.length() == 2);
10848 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10849 Smi::cast(args[1])->value());
10850 Top::PrintStack();
10851 OS::Abort();
10852 UNREACHABLE();
10853 return NULL;
10854}
10855
10856
lrn@chromium.org303ada72010-10-27 09:33:13 +000010857static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010858 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010859 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010860 Object* key = args[1];
10861
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010862 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010863 Object* o = cache->get(finger_index);
10864 if (o == key) {
10865 // The fastest case: hit the same place again.
10866 return cache->get(finger_index + 1);
10867 }
10868
10869 for (int i = finger_index - 2;
10870 i >= JSFunctionResultCache::kEntriesIndex;
10871 i -= 2) {
10872 o = cache->get(i);
10873 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010874 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010875 return cache->get(i + 1);
10876 }
10877 }
10878
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010879 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010880 ASSERT(size <= cache->length());
10881
10882 for (int i = size - 2; i > finger_index; i -= 2) {
10883 o = cache->get(i);
10884 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010885 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010886 return cache->get(i + 1);
10887 }
10888 }
10889
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010890 // There is no value in the cache. Invoke the function and cache result.
10891 HandleScope scope;
10892
10893 Handle<JSFunctionResultCache> cache_handle(cache);
10894 Handle<Object> key_handle(key);
10895 Handle<Object> value;
10896 {
10897 Handle<JSFunction> factory(JSFunction::cast(
10898 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
10899 // TODO(antonm): consider passing a receiver when constructing a cache.
10900 Handle<Object> receiver(Top::global_context()->global());
10901 // This handle is nor shared, nor used later, so it's safe.
10902 Object** argv[] = { key_handle.location() };
10903 bool pending_exception = false;
10904 value = Execution::Call(factory,
10905 receiver,
10906 1,
10907 argv,
10908 &pending_exception);
10909 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010910 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010911
10912#ifdef DEBUG
10913 cache_handle->JSFunctionResultCacheVerify();
10914#endif
10915
10916 // Function invocation may have cleared the cache. Reread all the data.
10917 finger_index = cache_handle->finger_index();
10918 size = cache_handle->size();
10919
10920 // If we have spare room, put new data into it, otherwise evict post finger
10921 // entry which is likely to be the least recently used.
10922 int index = -1;
10923 if (size < cache_handle->length()) {
10924 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
10925 index = size;
10926 } else {
10927 index = finger_index + JSFunctionResultCache::kEntrySize;
10928 if (index == cache_handle->length()) {
10929 index = JSFunctionResultCache::kEntriesIndex;
10930 }
10931 }
10932
10933 ASSERT(index % 2 == 0);
10934 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10935 ASSERT(index < cache_handle->length());
10936
10937 cache_handle->set(index, *key_handle);
10938 cache_handle->set(index + 1, *value);
10939 cache_handle->set_finger_index(index);
10940
10941#ifdef DEBUG
10942 cache_handle->JSFunctionResultCacheVerify();
10943#endif
10944
10945 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010946}
10947
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000010948
10949static MaybeObject* Runtime_NewMessageObject(Arguments args) {
10950 HandleScope scope;
10951 CONVERT_ARG_CHECKED(String, type, 0);
10952 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
10953 return *Factory::NewJSMessageObject(type,
10954 arguments,
10955 0,
10956 0,
10957 Factory::undefined_value(),
10958 Factory::undefined_value(),
10959 Factory::undefined_value());
10960}
10961
10962
10963static MaybeObject* Runtime_MessageGetType(Arguments args) {
10964 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10965 return message->type();
10966}
10967
10968
10969static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
10970 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10971 return message->arguments();
10972}
10973
10974
10975static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
10976 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10977 return Smi::FromInt(message->start_position());
10978}
10979
10980
10981static MaybeObject* Runtime_MessageGetScript(Arguments args) {
10982 CONVERT_CHECKED(JSMessageObject, message, args[0]);
10983 return message->script();
10984}
10985
10986
kasper.lund44510672008-07-25 07:37:58 +000010987#ifdef DEBUG
10988// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10989// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010990static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010991 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010992 HandleScope scope;
10993 Handle<JSArray> result = Factory::NewJSArray(0);
10994 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010995 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010996#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010997 { \
10998 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010999 Handle<String> name; \
11000 /* Inline runtime functions have an underscore in front of the name. */ \
11001 if (inline_runtime_functions) { \
11002 name = Factory::NewStringFromAscii( \
11003 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11004 } else { \
11005 name = Factory::NewStringFromAscii( \
11006 Vector<const char>(#Name, StrLength(#Name))); \
11007 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011008 Handle<JSArray> pair = Factory::NewJSArray(0); \
11009 SetElement(pair, 0, name); \
11010 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
11011 SetElement(result, index++, pair); \
11012 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011013 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011014 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011015 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011016 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011017 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011018#undef ADD_ENTRY
11019 return *result;
11020}
kasper.lund44510672008-07-25 07:37:58 +000011021#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011022
11023
lrn@chromium.org303ada72010-10-27 09:33:13 +000011024static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011025 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011026 CONVERT_CHECKED(String, format, args[0]);
11027 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011028 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011029 Logger::LogRuntime(chars, elms);
11030 return Heap::undefined_value();
11031}
11032
11033
lrn@chromium.org303ada72010-10-27 09:33:13 +000011034static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011035 UNREACHABLE(); // implemented as macro in the parser
11036 return NULL;
11037}
11038
11039
11040// ----------------------------------------------------------------------------
11041// Implementation of Runtime
11042
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011043#define F(name, number_of_args, result_size) \
11044 { Runtime::k##name, Runtime::RUNTIME, #name, \
11045 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011046
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011047
11048#define I(name, number_of_args, result_size) \
11049 { Runtime::kInline##name, Runtime::INLINE, \
11050 "_" #name, NULL, number_of_args, result_size },
11051
11052Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011053 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011054 INLINE_FUNCTION_LIST(I)
11055 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011056};
11057
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011058
lrn@chromium.org303ada72010-10-27 09:33:13 +000011059MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011060 ASSERT(dictionary != NULL);
11061 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11062 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011063 Object* name_symbol;
11064 { MaybeObject* maybe_name_symbol =
11065 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
11066 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11067 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011068 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011069 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11070 String::cast(name_symbol),
11071 Smi::FromInt(i),
11072 PropertyDetails(NONE, NORMAL));
11073 if (!maybe_dictionary->ToObject(&dictionary)) {
11074 // Non-recoverable failure. Calling code must restart heap
11075 // initialization.
11076 return maybe_dictionary;
11077 }
11078 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011079 }
11080 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011081}
11082
11083
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011084Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11085 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
11086 if (entry != kNotFound) {
11087 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
11088 int function_index = Smi::cast(smi_index)->value();
11089 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011090 }
11091 return NULL;
11092}
11093
11094
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011095Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
11096 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11097}
11098
11099
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011100void Runtime::PerformGC(Object* result) {
11101 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011102 if (failure->IsRetryAfterGC()) {
11103 // Try to do a garbage collection; ignore it if it fails. The C
11104 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011105 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011106 } else {
11107 // Handle last resort GC and make sure to allow future allocations
11108 // to grow the heap without causing GCs (if possible).
11109 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000011110 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011111 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011112}
11113
11114
11115} } // namespace v8::internal