blob: 19f362019275f132bb89c39ffe206604be1d7b10 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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"
35#include "compiler.h"
36#include "cpu.h"
37#include "dateparser.h"
38#include "debug.h"
39#include "execution.h"
40#include "jsregexp.h"
41#include "platform.h"
42#include "runtime.h"
43#include "scopeinfo.h"
44#include "v8threads.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000045#include "smart-pointer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
47namespace v8 { namespace internal {
48
49
50#define RUNTIME_ASSERT(value) do { \
51 if (!(value)) return IllegalOperation(); \
52} while (false)
53
54// Cast the given object to a value of the specified type and store
55// it in a variable with the given name. If the object is not of the
56// expected type call IllegalOperation and return.
57#define CONVERT_CHECKED(Type, name, obj) \
58 RUNTIME_ASSERT(obj->Is##Type()); \
59 Type* name = Type::cast(obj);
60
61#define CONVERT_ARG_CHECKED(Type, name, index) \
62 RUNTIME_ASSERT(args[index]->Is##Type()); \
63 Handle<Type> name = args.at<Type>(index);
64
kasper.lundbd3ec4e2008-07-09 11:06:54 +000065// Cast the given object to a boolean and store it in a variable with
66// the given name. If the object is not a boolean call IllegalOperation
67// and return.
68#define CONVERT_BOOLEAN_CHECKED(name, obj) \
69 RUNTIME_ASSERT(obj->IsBoolean()); \
70 bool name = (obj)->IsTrue();
71
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072// Cast the given object to a double and store it in a variable with
73// the given name. If the object is not a number (as opposed to
74// the number not-a-number) call IllegalOperation and return.
75#define CONVERT_DOUBLE_CHECKED(name, obj) \
76 RUNTIME_ASSERT(obj->IsNumber()); \
77 double name = (obj)->Number();
78
79// Call the specified converter on the object *comand store the result in
80// a variable of the specified type with the given name. If the
81// object is not a Number call IllegalOperation and return.
82#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
83 RUNTIME_ASSERT(obj->IsNumber()); \
84 type name = NumberTo##Type(obj);
85
86// Non-reentrant string buffer for efficient general use in this file.
87static StaticResource<StringInputBuffer> string_input_buffer;
88
89
90static Object* IllegalOperation() {
91 return Top::Throw(Heap::illegal_access_symbol());
92}
93
94
95static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
96 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000097 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098}
99
100
ager@chromium.org236ad962008-09-25 09:45:57 +0000101static Handle<Map> ComputeObjectLiteralMap(
102 Handle<Context> context,
103 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000104 bool* is_result_from_cache) {
ager@chromium.org32912102009-01-16 10:38:43 +0000105 int number_of_properties = constant_properties->length() / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000106 if (FLAG_canonicalize_object_literal_maps) {
107 // First find prefix of consecutive symbol keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000108 int number_of_symbol_keys = 0;
109 while ((number_of_symbol_keys < number_of_properties) &&
110 (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) {
111 number_of_symbol_keys++;
112 }
113 // Based on the number of prefix symbols key we decide whether
114 // to use the map cache in the global context.
115 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000116 if ((number_of_symbol_keys == number_of_properties) &&
117 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000118 // Create the fixed array with the key.
119 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
120 for (int i = 0; i < number_of_symbol_keys; i++) {
121 keys->set(i, constant_properties->get(i*2));
122 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000123 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000124 return Factory::ObjectLiteralMapFromCache(context, keys);
125 }
126 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000127 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000128 return Factory::CopyMap(
129 Handle<Map>(context->object_function()->initial_map()),
130 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000131}
132
133
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
135 HandleScope scope;
136 ASSERT(args.length() == 3);
137 // Copy the arguments.
138 Handle<FixedArray> literals = args.at<FixedArray>(0);
139 int literals_index = Smi::cast(args[1])->value();
140 Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000141
142 // Get the global context from the literals array. This is the
143 // context in which the function was created and we use the object
144 // function from this context to create the object literal. We do
145 // not use the object function from the current global context
146 // because this might be the object function from another context
147 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000148 Handle<Context> context =
149 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
150
151 bool is_result_from_cache;
152 Handle<Map> map = ComputeObjectLiteralMap(context,
153 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000154 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155
ager@chromium.org236ad962008-09-25 09:45:57 +0000156 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
ager@chromium.org32912102009-01-16 10:38:43 +0000157 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000159 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
160 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000161 for (int index = 0; index < length; index +=2) {
162 Handle<Object> key(constant_properties->get(index+0));
163 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000164 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165 uint32_t element_index = 0;
166 if (key->IsSymbol()) {
167 // If key is a symbol it is not an array element.
168 Handle<String> name(String::cast(*key));
169 ASSERT(!name->AsArrayIndex(&element_index));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000170 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171 } else if (Array::IndexFromObject(*key, &element_index)) {
172 // Array index (uint32).
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000173 result = SetElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000174 } else {
175 // Non-uint32 number.
176 ASSERT(key->IsNumber());
177 double num = key->Number();
178 char arr[100];
179 Vector<char> buffer(arr, ARRAY_SIZE(arr));
180 const char* str = DoubleToCString(num, buffer);
181 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000182 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000184 // If setting the property on the boilerplate throws an
185 // exception, the exception is converted to an empty handle in
186 // the handle based operations. In that case, we need to
187 // convert back to an exception.
188 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189 }
190 }
191
192 // Update the functions literal and return the boilerplate.
193 literals->set(literals_index, *boilerplate);
194
195 return *boilerplate;
196}
197
198
199static Object* Runtime_CreateArrayLiteral(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000200 // Takes a FixedArray of elements containing the literal elements of
201 // the array literal and produces JSArray with those elements.
202 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000203 // which contains the context from which to get the Array function
204 // to use for creating the array literal.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000205 ASSERT(args.length() == 2);
206 CONVERT_CHECKED(FixedArray, elements, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000207 CONVERT_CHECKED(FixedArray, literals, args[1]);
ager@chromium.org236ad962008-09-25 09:45:57 +0000208 JSFunction* constructor =
209 JSFunction::GlobalContextFromLiterals(literals)->array_function();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210 // Create the JSArray.
211 Object* object = Heap::AllocateJSObject(constructor);
212 if (object->IsFailure()) return object;
213
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000214 // Copy the elements.
215 Object* content = elements->Copy();
216 if (content->IsFailure()) return content;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217
218 // Set the elements.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000219 JSArray::cast(object)->SetContent(FixedArray::cast(content));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220 return object;
221}
222
223
ager@chromium.org32912102009-01-16 10:38:43 +0000224static Object* Runtime_CreateCatchExtensionObject(Arguments args) {
225 ASSERT(args.length() == 2);
226 CONVERT_CHECKED(String, key, args[0]);
227 Object* value = args[1];
228 // Create a catch context extension object.
229 JSFunction* constructor =
230 Top::context()->global_context()->context_extension_function();
231 Object* object = Heap::AllocateJSObject(constructor);
232 if (object->IsFailure()) return object;
233 // Assign the exception value to the catch variable and make sure
234 // that the catch variable is DontDelete.
235 value = JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
236 if (value->IsFailure()) return value;
237 return object;
238}
239
240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241static Object* Runtime_ClassOf(Arguments args) {
242 NoHandleAllocation ha;
243 ASSERT(args.length() == 1);
244 Object* obj = args[0];
245 if (!obj->IsJSObject()) return Heap::null_value();
246 return JSObject::cast(obj)->class_name();
247}
248
ager@chromium.org7c537e22008-10-16 08:43:32 +0000249
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000250static Object* Runtime_HasStringClass(Arguments args) {
251 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::String_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000252}
253
254
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000255static Object* Runtime_HasDateClass(Arguments args) {
256 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Date_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000257}
258
259
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000260static Object* Runtime_HasArrayClass(Arguments args) {
261 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Array_symbol()));
262}
263
264
265static Object* Runtime_HasFunctionClass(Arguments args) {
266 return Heap::ToBoolean(
267 args[0]->HasSpecificClassOf(Heap::function_class_symbol()));
268}
269
270
271static Object* Runtime_HasNumberClass(Arguments args) {
272 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Number_symbol()));
273}
274
275
276static Object* Runtime_HasBooleanClass(Arguments args) {
277 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Boolean_symbol()));
278}
279
280
281static Object* Runtime_HasArgumentsClass(Arguments args) {
282 return Heap::ToBoolean(
283 args[0]->HasSpecificClassOf(Heap::Arguments_symbol()));
284}
285
286
287static Object* Runtime_HasRegExpClass(Arguments args) {
288 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::RegExp_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000289}
290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000291
292static Object* Runtime_IsInPrototypeChain(Arguments args) {
293 NoHandleAllocation ha;
294 ASSERT(args.length() == 2);
295 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
296 Object* O = args[0];
297 Object* V = args[1];
298 while (true) {
299 Object* prototype = V->GetPrototype();
300 if (prototype->IsNull()) return Heap::false_value();
301 if (O == prototype) return Heap::true_value();
302 V = prototype;
303 }
304}
305
306
307static Object* Runtime_IsConstructCall(Arguments args) {
308 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000309 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000310 JavaScriptFrameIterator it;
311 return Heap::ToBoolean(it.frame()->IsConstructor());
312}
313
314
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315static Object* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000316 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000318 CONVERT_CHECKED(JSRegExp, raw_re, args[0]);
319 Handle<JSRegExp> re(raw_re);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 CONVERT_CHECKED(String, raw_pattern, args[1]);
321 Handle<String> pattern(raw_pattern);
322 CONVERT_CHECKED(String, raw_flags, args[2]);
323 Handle<String> flags(raw_flags);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000324 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
325 if (result.is_null()) return Failure::Exception();
326 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327}
328
329
330static Object* Runtime_CreateApiFunction(Arguments args) {
331 HandleScope scope;
332 ASSERT(args.length() == 1);
333 CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]);
334 Handle<FunctionTemplateInfo> data(raw_data);
335 return *Factory::CreateApiFunction(data);
336}
337
338
339static Object* Runtime_IsTemplate(Arguments args) {
340 ASSERT(args.length() == 1);
341 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000342 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 return Heap::ToBoolean(result);
344}
345
346
347static Object* Runtime_GetTemplateField(Arguments args) {
348 ASSERT(args.length() == 2);
349 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000351 int index = field->value();
352 int offset = index * kPointerSize + HeapObject::kHeaderSize;
353 InstanceType type = templ->map()->instance_type();
354 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
355 type == OBJECT_TEMPLATE_INFO_TYPE);
356 RUNTIME_ASSERT(offset > 0);
357 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
358 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
359 } else {
360 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
361 }
362 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363}
364
365
ager@chromium.org870a0b62008-11-04 11:43:05 +0000366static Object* Runtime_DisableAccessChecks(Arguments args) {
367 ASSERT(args.length() == 1);
368 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000369 Map* old_map = object->map();
370 bool needs_access_checks = old_map->is_access_check_needed();
371 if (needs_access_checks) {
372 // Copy map so it won't interfere constructor's initial map.
373 Object* new_map = old_map->CopyDropTransitions();
374 if (new_map->IsFailure()) return new_map;
375
376 Map::cast(new_map)->set_is_access_check_needed(false);
377 object->set_map(Map::cast(new_map));
378 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000379 return needs_access_checks ? Heap::true_value() : Heap::false_value();
380}
381
382
383static Object* Runtime_EnableAccessChecks(Arguments args) {
384 ASSERT(args.length() == 1);
385 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000386 Map* old_map = object->map();
387 if (!old_map->is_access_check_needed()) {
388 // Copy map so it won't interfere constructor's initial map.
389 Object* new_map = old_map->CopyDropTransitions();
390 if (new_map->IsFailure()) return new_map;
391
392 Map::cast(new_map)->set_is_access_check_needed(true);
393 object->set_map(Map::cast(new_map));
394 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000395 return Heap::undefined_value();
396}
397
398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
400 HandleScope scope;
401 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
402 Handle<Object> args[2] = { type_handle, name };
403 Handle<Object> error =
404 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
405 return Top::Throw(*error);
406}
407
408
409static Object* Runtime_DeclareGlobals(Arguments args) {
410 HandleScope scope;
411 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
412
413 CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
414 Handle<Context> context = args.at<Context>(1);
415 bool is_eval = Smi::cast(args[2])->value() == 1;
416
417 // Compute the property attributes. According to ECMA-262, section
418 // 13, page 71, the property must be read-only and
419 // non-deletable. However, neither SpiderMonkey nor KJS creates the
420 // property as read-only, so we don't either.
421 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
422
423 // Only optimize the object if we intend to add more than 5 properties.
424 OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
425
426 // Traverse the name/value pairs and set the properties.
427 int length = pairs->length();
428 for (int i = 0; i < length; i += 2) {
429 HandleScope scope;
430 Handle<String> name(String::cast(pairs->get(i)));
431 Handle<Object> value(pairs->get(i + 1));
432
433 // We have to declare a global const property. To capture we only
434 // assign to it when evaluating the assignment for "const x =
435 // <expr>" the initial value is the hole.
436 bool is_const_property = value->IsTheHole();
437
438 if (value->IsUndefined() || is_const_property) {
439 // Lookup the property in the global object, and don't set the
440 // value of the variable if the property is already there.
441 LookupResult lookup;
442 global->Lookup(*name, &lookup);
443 if (lookup.IsProperty()) {
444 // Determine if the property is local by comparing the holder
445 // against the global object. The information will be used to
446 // avoid throwing re-declaration errors when declaring
447 // variables or constants that exist in the prototype chain.
448 bool is_local = (*global == lookup.holder());
449 // Get the property attributes and determine if the property is
450 // read-only.
451 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
452 bool is_read_only = (attributes & READ_ONLY) != 0;
453 if (lookup.type() == INTERCEPTOR) {
454 // If the interceptor says the property is there, we
455 // just return undefined without overwriting the property.
456 // Otherwise, we continue to setting the property.
457 if (attributes != ABSENT) {
458 // Check if the existing property conflicts with regards to const.
459 if (is_local && (is_read_only || is_const_property)) {
460 const char* type = (is_read_only) ? "const" : "var";
461 return ThrowRedeclarationError(type, name);
462 };
463 // The property already exists without conflicting: Go to
464 // the next declaration.
465 continue;
466 }
467 // Fall-through and introduce the absent property by using
468 // SetProperty.
469 } else {
470 if (is_local && (is_read_only || is_const_property)) {
471 const char* type = (is_read_only) ? "const" : "var";
472 return ThrowRedeclarationError(type, name);
473 }
474 // The property already exists without conflicting: Go to
475 // the next declaration.
476 continue;
477 }
478 }
479 } else {
480 // Copy the function and update its context. Use it as value.
481 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
482 Handle<JSFunction> function =
483 Factory::NewFunctionFromBoilerplate(boilerplate, context);
484 value = function;
485 }
486
487 LookupResult lookup;
488 global->LocalLookup(*name, &lookup);
489
490 PropertyAttributes attributes = is_const_property
491 ? static_cast<PropertyAttributes>(base | READ_ONLY)
492 : base;
493
494 if (lookup.IsProperty()) {
495 // There's a local property that we need to overwrite because
496 // we're either declaring a function or there's an interceptor
497 // that claims the property is absent.
498
499 // Check for conflicting re-declarations. We cannot have
500 // conflicting types in case of intercepted properties because
501 // they are absent.
502 if (lookup.type() != INTERCEPTOR &&
503 (lookup.IsReadOnly() || is_const_property)) {
504 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
505 return ThrowRedeclarationError(type, name);
506 }
507 SetProperty(global, name, value, attributes);
508 } else {
509 // If a property with this name does not already exist on the
510 // global object add the property locally. We take special
511 // precautions to always add it as a local property even in case
512 // of callbacks in the prototype chain (this rules out using
513 // SetProperty). Also, we must use the handle-based version to
514 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000515 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000516 }
517 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000518
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000519 return Heap::undefined_value();
520}
521
522
523static Object* Runtime_DeclareContextSlot(Arguments args) {
524 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000525 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526
ager@chromium.org7c537e22008-10-16 08:43:32 +0000527 CONVERT_ARG_CHECKED(Context, context, 0);
528 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000530 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531 ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000532 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000533
534 // Declarations are always done in the function context.
535 context = Handle<Context>(context->fcontext());
536
537 int index;
538 PropertyAttributes attributes;
539 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000540 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541 context->Lookup(name, flags, &index, &attributes);
542
543 if (attributes != ABSENT) {
544 // The name was declared before; check for conflicting
545 // re-declarations: This is similar to the code in parser.cc in
546 // the AstBuildingParser::Declare function.
547 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
548 // Functions are not read-only.
549 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
550 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
551 return ThrowRedeclarationError(type, name);
552 }
553
554 // Initialize it if necessary.
555 if (*initial_value != NULL) {
556 if (index >= 0) {
557 // The variable or constant context slot should always be in
558 // the function context; not in any outer context nor in the
559 // arguments object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000560 ASSERT(holder.is_identical_to(context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000561 if (((attributes & READ_ONLY) == 0) ||
562 context->get(index)->IsTheHole()) {
563 context->set(index, *initial_value);
564 }
565 } else {
566 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000567 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 SetProperty(context_ext, name, initial_value, mode);
569 }
570 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000573 // The property is not in the function context. It needs to be
574 // "declared" in the function context's extension context, or in the
575 // global context.
576 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000577 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000578 // The function context's extension context exists - use it.
579 context_ext = Handle<JSObject>(context->extension());
580 } else {
581 // The function context's extension context does not exists - allocate
582 // it.
583 context_ext = Factory::NewJSObject(Top::context_extension_function());
584 // And store it in the extension slot.
585 context->set_extension(*context_ext);
586 }
587 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588
ager@chromium.org7c537e22008-10-16 08:43:32 +0000589 // Declare the property by setting it to the initial value if provided,
590 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
591 // constant declarations).
592 ASSERT(!context_ext->HasLocalProperty(*name));
593 Handle<Object> value(Heap::undefined_value());
594 if (*initial_value != NULL) value = initial_value;
595 SetProperty(context_ext, name, value, mode);
596 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
597 }
598
599 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600}
601
602
603static Object* Runtime_InitializeVarGlobal(Arguments args) {
604 NoHandleAllocation nha;
605
606 // Determine if we need to assign to the variable if it already
607 // exists (based on the number of arguments).
608 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
609 bool assign = args.length() == 2;
610
611 CONVERT_ARG_CHECKED(String, name, 0);
612 GlobalObject* global = Top::context()->global();
613
614 // According to ECMA-262, section 12.2, page 62, the property must
615 // not be deletable.
616 PropertyAttributes attributes = DONT_DELETE;
617
618 // Lookup the property locally in the global object. If it isn't
619 // there, we add the property and take special precautions to always
620 // add it as a local property even in case of callbacks in the
621 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000622 // We have IgnoreAttributesAndSetLocalProperty for this.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 LookupResult lookup;
624 global->LocalLookup(*name, &lookup);
625 if (!lookup.IsProperty()) {
626 Object* value = (assign) ? args[1] : Heap::undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000627 return global->IgnoreAttributesAndSetLocalProperty(*name,
628 value,
629 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630 }
631
632 // Determine if this is a redeclaration of something read-only.
633 if (lookup.IsReadOnly()) {
634 return ThrowRedeclarationError("const", name);
635 }
636
637 // Determine if this is a redeclaration of an intercepted read-only
638 // property and figure out if the property exists at all.
639 bool found = true;
640 PropertyType type = lookup.type();
641 if (type == INTERCEPTOR) {
642 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
643 if (intercepted == ABSENT) {
644 // The interceptor claims the property isn't there. We need to
645 // make sure to introduce it.
646 found = false;
647 } else if ((intercepted & READ_ONLY) != 0) {
648 // The property is present, but read-only. Since we're trying to
649 // overwrite it with a variable declaration we must throw a
650 // re-declaration error.
651 return ThrowRedeclarationError("const", name);
652 }
653 // Restore global object from context (in case of GC).
654 global = Top::context()->global();
655 }
656
657 if (found && !assign) {
658 // The global property is there and we're not assigning any value
659 // to it. Just return.
660 return Heap::undefined_value();
661 }
662
663 // Assign the value (or undefined) to the property.
664 Object* value = (assign) ? args[1] : Heap::undefined_value();
665 return global->SetProperty(&lookup, *name, value, attributes);
666}
667
668
669static Object* Runtime_InitializeConstGlobal(Arguments args) {
670 // All constants are declared with an initial value. The name
671 // of the constant is the first argument and the initial value
672 // is the second.
673 RUNTIME_ASSERT(args.length() == 2);
674 CONVERT_ARG_CHECKED(String, name, 0);
675 Handle<Object> value = args.at<Object>(1);
676
677 // Get the current global object from top.
678 GlobalObject* global = Top::context()->global();
679
680 // According to ECMA-262, section 12.2, page 62, the property must
681 // not be deletable. Since it's a const, it must be READ_ONLY too.
682 PropertyAttributes attributes =
683 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
684
685 // Lookup the property locally in the global object. If it isn't
686 // there, we add the property and take special precautions to always
687 // add it as a local property even in case of callbacks in the
688 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000689 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000690 LookupResult lookup;
691 global->LocalLookup(*name, &lookup);
692 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000693 return global->IgnoreAttributesAndSetLocalProperty(*name,
694 *value,
695 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 }
697
698 // Determine if this is a redeclaration of something not
699 // read-only. In case the result is hidden behind an interceptor we
700 // need to ask it for the property attributes.
701 if (!lookup.IsReadOnly()) {
702 if (lookup.type() != INTERCEPTOR) {
703 return ThrowRedeclarationError("var", name);
704 }
705
706 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
707
708 // Throw re-declaration error if the intercepted property is present
709 // but not read-only.
710 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
711 return ThrowRedeclarationError("var", name);
712 }
713
714 // Restore global object from context (in case of GC) and continue
715 // with setting the value because the property is either absent or
716 // read-only. We also have to do redo the lookup.
717 global = Top::context()->global();
718
719 // BUG 1213579: Handle the case where we have to set a read-only
720 // property through an interceptor and only do it if it's
721 // uninitialized, e.g. the hole. Nirk...
722 global->SetProperty(*name, *value, attributes);
723 return *value;
724 }
725
726 // Set the value, but only we're assigning the initial value to a
727 // constant. For now, we determine this by checking if the
728 // current value is the hole.
729 PropertyType type = lookup.type();
730 if (type == FIELD) {
731 FixedArray* properties = global->properties();
732 int index = lookup.GetFieldIndex();
733 if (properties->get(index)->IsTheHole()) {
734 properties->set(index, *value);
735 }
736 } else if (type == NORMAL) {
737 Dictionary* dictionary = global->property_dictionary();
738 int entry = lookup.GetDictionaryEntry();
739 if (dictionary->ValueAt(entry)->IsTheHole()) {
740 dictionary->ValueAtPut(entry, *value);
741 }
742 } else {
743 // Ignore re-initialization of constants that have already been
744 // assigned a function value.
745 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
746 }
747
748 // Use the set value as the result of the operation.
749 return *value;
750}
751
752
753static Object* Runtime_InitializeConstContextSlot(Arguments args) {
754 HandleScope scope;
755 ASSERT(args.length() == 3);
756
757 Handle<Object> value(args[0]);
758 ASSERT(!value->IsTheHole());
759 CONVERT_ARG_CHECKED(Context, context, 1);
760 Handle<String> name(String::cast(args[2]));
761
762 // Initializations are always done in the function context.
763 context = Handle<Context>(context->fcontext());
764
765 int index;
766 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000767 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000768 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769 context->Lookup(name, flags, &index, &attributes);
770
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000771 // In most situations, the property introduced by the const
772 // declaration should be present in the context extension object.
773 // However, because declaration and initialization are separate, the
774 // property might have been deleted (if it was introduced by eval)
775 // before we reach the initialization point.
776 //
777 // Example:
778 //
779 // function f() { eval("delete x; const x;"); }
780 //
781 // In that case, the initialization behaves like a normal assignment
782 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000784 // Property was found in a context.
785 if (holder->IsContext()) {
786 // The holder cannot be the function context. If it is, there
787 // should have been a const redeclaration error when declaring
788 // the const property.
789 ASSERT(!holder.is_identical_to(context));
790 if ((attributes & READ_ONLY) == 0) {
791 Handle<Context>::cast(holder)->set(index, *value);
792 }
793 } else {
794 // The holder is an arguments object.
795 ASSERT((attributes & READ_ONLY) == 0);
796 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 }
798 return *value;
799 }
800
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000801 // The property could not be found, we introduce it in the global
802 // context.
803 if (attributes == ABSENT) {
804 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
805 SetProperty(global, name, value, NONE);
806 return *value;
807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000809 // The property was present in a context extension object.
810 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000812 if (*context_ext == context->extension()) {
813 // This is the property that was introduced by the const
814 // declaration. Set it if it hasn't been set before. NOTE: We
815 // cannot use GetProperty() to get the current value as it
816 // 'unholes' the value.
817 LookupResult lookup;
818 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
819 ASSERT(lookup.IsProperty()); // the property was declared
820 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
821
822 PropertyType type = lookup.type();
823 if (type == FIELD) {
824 FixedArray* properties = context_ext->properties();
825 int index = lookup.GetFieldIndex();
826 if (properties->get(index)->IsTheHole()) {
827 properties->set(index, *value);
828 }
829 } else if (type == NORMAL) {
830 Dictionary* dictionary = context_ext->property_dictionary();
831 int entry = lookup.GetDictionaryEntry();
832 if (dictionary->ValueAt(entry)->IsTheHole()) {
833 dictionary->ValueAtPut(entry, *value);
834 }
835 } else {
836 // We should not reach here. Any real, named property should be
837 // either a field or a dictionary slot.
838 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839 }
840 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000841 // The property was found in a different context extension object.
842 // Set it if it is not a read-only property.
843 if ((attributes & READ_ONLY) == 0) {
844 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
845 // Setting a property might throw an exception. Exceptions
846 // are converted to empty handles in handle operations. We
847 // need to convert back to exceptions here.
848 if (set.is_null()) {
849 ASSERT(Top::has_pending_exception());
850 return Failure::Exception();
851 }
852 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000853 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000854
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855 return *value;
856}
857
858
859static Object* Runtime_RegExpExec(Arguments args) {
860 HandleScope scope;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000861 ASSERT(args.length() == 4);
ager@chromium.org236ad962008-09-25 09:45:57 +0000862 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
863 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864 CONVERT_CHECKED(String, raw_subject, args[1]);
865 Handle<String> subject(raw_subject);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000866 // Due to the way the JS files are constructed this must be less than the
867 // length of a string, i.e. it is always a Smi. We check anyway for security.
868 CONVERT_CHECKED(Smi, index, args[2]);
869 CONVERT_CHECKED(JSArray, raw_last_match_info, args[3]);
870 Handle<JSArray> last_match_info(raw_last_match_info);
871 CHECK(last_match_info->HasFastElements());
872 Handle<Object> result = RegExpImpl::Exec(regexp,
873 subject,
874 index->value(),
875 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000876 if (result.is_null()) return Failure::Exception();
877 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000878}
879
880
881static Object* Runtime_RegExpExecGlobal(Arguments args) {
882 HandleScope scope;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000883 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000884 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
885 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 CONVERT_CHECKED(String, raw_subject, args[1]);
887 Handle<String> subject(raw_subject);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000888 CONVERT_CHECKED(JSArray, raw_last_match_info, args[2]);
889 Handle<JSArray> last_match_info(raw_last_match_info);
890 CHECK(last_match_info->HasFastElements());
891 Handle<Object> result =
892 RegExpImpl::ExecGlobal(regexp, subject, last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000893 if (result.is_null()) return Failure::Exception();
894 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895}
896
897
898static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
899 HandleScope scope;
900 ASSERT(args.length() == 4);
901 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
902 int index = Smi::cast(args[1])->value();
903 Handle<String> pattern = args.at<String>(2);
904 Handle<String> flags = args.at<String>(3);
905
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000906 // Get the RegExp function from the context in the literals array.
907 // This is the RegExp function from the context in which the
908 // function was created. We do not use the RegExp function from the
909 // current global context because this might be the RegExp function
910 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000911 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +0000912 Handle<JSFunction>(
913 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914 // Compute the regular expression literal.
915 bool has_pending_exception;
916 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000917 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
918 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919 if (has_pending_exception) {
920 ASSERT(Top::has_pending_exception());
921 return Failure::Exception();
922 }
923 literals->set(index, *regexp);
924 return *regexp;
925}
926
927
928static Object* Runtime_FunctionGetName(Arguments args) {
929 NoHandleAllocation ha;
930 ASSERT(args.length() == 1);
931
932 CONVERT_CHECKED(JSFunction, f, args[0]);
933 return f->shared()->name();
934}
935
936
ager@chromium.org236ad962008-09-25 09:45:57 +0000937static Object* Runtime_FunctionSetName(Arguments args) {
938 NoHandleAllocation ha;
939 ASSERT(args.length() == 2);
940
941 CONVERT_CHECKED(JSFunction, f, args[0]);
942 CONVERT_CHECKED(String, name, args[1]);
943 f->shared()->set_name(name);
944 return Heap::undefined_value();
945}
946
947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948static Object* Runtime_FunctionGetScript(Arguments args) {
949 HandleScope scope;
950 ASSERT(args.length() == 1);
951
952 CONVERT_CHECKED(JSFunction, fun, args[0]);
953 Handle<Object> script = Handle<Object>(fun->shared()->script());
954 if (!script->IsScript()) return Heap::undefined_value();
955
956 return *GetScriptWrapper(Handle<Script>::cast(script));
957}
958
959
960static Object* Runtime_FunctionGetSourceCode(Arguments args) {
961 NoHandleAllocation ha;
962 ASSERT(args.length() == 1);
963
964 CONVERT_CHECKED(JSFunction, f, args[0]);
965 return f->shared()->GetSourceCode();
966}
967
968
969static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
970 NoHandleAllocation ha;
971 ASSERT(args.length() == 1);
972
973 CONVERT_CHECKED(JSFunction, fun, args[0]);
974 int pos = fun->shared()->start_position();
975 return Smi::FromInt(pos);
976}
977
978
979static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
980 NoHandleAllocation ha;
981 ASSERT(args.length() == 2);
982
983 CONVERT_CHECKED(JSFunction, fun, args[0]);
984 CONVERT_CHECKED(String, name, args[1]);
985 fun->SetInstanceClassName(name);
986 return Heap::undefined_value();
987}
988
989
990static Object* Runtime_FunctionSetLength(Arguments args) {
991 NoHandleAllocation ha;
992 ASSERT(args.length() == 2);
993
994 CONVERT_CHECKED(JSFunction, fun, args[0]);
995 CONVERT_CHECKED(Smi, length, args[1]);
996 fun->shared()->set_length(length->value());
997 return length;
998}
999
1000
1001static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001002 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 ASSERT(args.length() == 2);
1004
1005 CONVERT_CHECKED(JSFunction, fun, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001006 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
1007 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008 return args[0]; // return TOS
1009}
1010
1011
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001012static Object* Runtime_FunctionIsAPIFunction(Arguments args) {
1013 NoHandleAllocation ha;
1014 ASSERT(args.length() == 1);
1015
1016 CONVERT_CHECKED(JSFunction, f, args[0]);
1017 // The function_data field of the shared function info is used exclusively by
1018 // the API.
1019 return !f->shared()->function_data()->IsUndefined() ? Heap::true_value()
1020 : Heap::false_value();
1021}
1022
1023
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001024static Object* Runtime_SetCode(Arguments args) {
1025 HandleScope scope;
1026 ASSERT(args.length() == 2);
1027
1028 CONVERT_CHECKED(JSFunction, raw_target, args[0]);
1029 Handle<JSFunction> target(raw_target);
1030 Handle<Object> code = args.at<Object>(1);
1031
1032 Handle<Context> context(target->context());
1033
1034 if (!code->IsNull()) {
1035 RUNTIME_ASSERT(code->IsJSFunction());
1036 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
1037 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
1038 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
1039 return Failure::Exception();
1040 }
1041 // Set the code, formal parameter count, and the length of the target
1042 // function.
1043 target->set_code(fun->code());
1044 target->shared()->set_length(fun->shared()->length());
1045 target->shared()->set_formal_parameter_count(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001046 fun->shared()->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001047 // Set the source code of the target function to undefined.
1048 // SetCode is only used for built-in constructors like String,
1049 // Array, and Object, and some web code
1050 // doesn't like seeing source code for constructors.
1051 target->shared()->set_script(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052 context = Handle<Context>(fun->context());
1053
1054 // Make sure we get a fresh copy of the literal vector to avoid
1055 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001056 int number_of_literals = fun->NumberOfLiterals();
1057 Handle<FixedArray> literals =
1058 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001060 // Insert the object, regexp and array functions in the literals
1061 // array prefix. These are the functions that will be used when
1062 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001063 literals->set(JSFunction::kLiteralGlobalContextIndex,
1064 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001066 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001067 }
1068
1069 target->set_context(*context);
1070 return *target;
1071}
1072
1073
1074static Object* CharCodeAt(String* subject, Object* index) {
1075 uint32_t i = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001076 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077 // Flatten the string. If someone wants to get a char at an index
1078 // in a cons string, it is likely that more indices will be
1079 // accessed.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001080 subject->TryFlattenIfNotFlat(StringShape(subject));
ager@chromium.org870a0b62008-11-04 11:43:05 +00001081 StringShape shape(subject);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001082 if (i >= static_cast<uint32_t>(subject->length(shape))) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001083 return Heap::nan_value();
1084 }
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001085 return Smi::FromInt(subject->Get(shape, i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086}
1087
1088
1089static Object* Runtime_StringCharCodeAt(Arguments args) {
1090 NoHandleAllocation ha;
1091 ASSERT(args.length() == 2);
1092
1093 CONVERT_CHECKED(String, subject, args[0]);
1094 Object* index = args[1];
1095 return CharCodeAt(subject, index);
1096}
1097
1098
1099static Object* Runtime_CharFromCode(Arguments args) {
1100 NoHandleAllocation ha;
1101 ASSERT(args.length() == 1);
1102 uint32_t code;
1103 if (Array::IndexFromObject(args[0], &code)) {
1104 if (code <= 0xffff) {
1105 return Heap::LookupSingleCharacterStringFromCode(code);
1106 }
1107 }
1108 return Heap::empty_string();
1109}
1110
1111
ager@chromium.org7c537e22008-10-16 08:43:32 +00001112// Cap on the maximal shift in the Boyer-Moore implementation. By setting a
1113// limit, we can fix the size of tables.
1114static const int kBMMaxShift = 0xff;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001115// Reduce alphabet to this size.
1116static const int kBMAlphabetSize = 0x100;
1117// For patterns below this length, the skip length of Boyer-Moore is too short
1118// to compensate for the algorithmic overhead compared to simple brute force.
1119static const int kBMMinPatternLength = 5;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120
ager@chromium.org7c537e22008-10-16 08:43:32 +00001121// Holds the two buffers used by Boyer-Moore string search's Good Suffix
1122// shift. Only allows the last kBMMaxShift characters of the needle
1123// to be indexed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001124class BMGoodSuffixBuffers {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001125 public:
1126 BMGoodSuffixBuffers() {}
1127 inline void init(int needle_length) {
1128 ASSERT(needle_length > 1);
1129 int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift;
1130 int len = needle_length - start;
1131 biased_suffixes_ = suffixes_ - start;
1132 biased_good_suffix_shift_ = good_suffix_shift_ - start;
1133 for (int i = 0; i <= len; i++) {
1134 good_suffix_shift_[i] = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001136 }
1137 inline int& suffix(int index) {
1138 ASSERT(biased_suffixes_ + index >= suffixes_);
1139 return biased_suffixes_[index];
1140 }
1141 inline int& shift(int index) {
1142 ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_);
1143 return biased_good_suffix_shift_[index];
1144 }
1145 private:
1146 int suffixes_[kBMMaxShift + 1];
1147 int good_suffix_shift_[kBMMaxShift + 1];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001148 int* biased_suffixes_;
1149 int* biased_good_suffix_shift_;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001150 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers);
1151};
1152
1153// buffers reused by BoyerMoore
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001154static int bad_char_occurrence[kBMAlphabetSize];
ager@chromium.org7c537e22008-10-16 08:43:32 +00001155static BMGoodSuffixBuffers bmgs_buffers;
1156
1157// Compute the bad-char table for Boyer-Moore in the static buffer.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001158template <typename pchar>
1159static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern,
1160 int start) {
1161 // Run forwards to populate bad_char_table, so that *last* instance
1162 // of character equivalence class is the one registered.
1163 // Notice: Doesn't include the last character.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001164 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1
1165 : kBMAlphabetSize;
1166 if (start == 0) { // All patterns less than kBMMaxShift in length.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001167 memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001168 } else {
1169 for (int i = 0; i < table_size; i++) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001170 bad_char_occurrence[i] = start - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001171 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001172 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001173 for (int i = start; i < pattern.length() - 1; i++) {
1174 pchar c = pattern[i];
1175 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001176 bad_char_occurrence[bucket] = i;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001177 }
1178}
1179
1180template <typename pchar>
1181static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001182 int start) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001183 int m = pattern.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001184 int len = m - start;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001185 // Compute Good Suffix tables.
1186 bmgs_buffers.init(m);
1187
1188 bmgs_buffers.shift(m-1) = 1;
1189 bmgs_buffers.suffix(m) = m + 1;
1190 pchar last_char = pattern[m - 1];
1191 int suffix = m + 1;
1192 for (int i = m; i > start;) {
1193 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) {
1194 if (bmgs_buffers.shift(suffix) == len) {
1195 bmgs_buffers.shift(suffix) = suffix - i;
1196 }
1197 suffix = bmgs_buffers.suffix(suffix);
1198 }
1199 i--;
1200 suffix--;
1201 bmgs_buffers.suffix(i) = suffix;
1202 if (suffix == m) {
1203 // No suffix to extend, so we check against last_char only.
1204 while (i > start && pattern[i - 1] != last_char) {
1205 if (bmgs_buffers.shift(m) == len) {
1206 bmgs_buffers.shift(m) = m - i;
1207 }
1208 i--;
1209 bmgs_buffers.suffix(i) = m;
1210 }
1211 if (i > start) {
1212 i--;
1213 suffix--;
1214 bmgs_buffers.suffix(i) = suffix;
1215 }
1216 }
1217 }
1218 if (suffix < m) {
1219 for (int i = start; i <= m; i++) {
1220 if (bmgs_buffers.shift(i) == len) {
1221 bmgs_buffers.shift(i) = suffix - start;
1222 }
1223 if (i == suffix) {
1224 suffix = bmgs_buffers.suffix(suffix);
1225 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 }
1227 }
1228}
1229
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001230template <typename schar, typename pchar>
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001231static inline int CharOccurrence(int char_code) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001232 if (sizeof(schar) == 1) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001233 return bad_char_occurrence[char_code];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001234 }
1235 if (sizeof(pchar) == 1) {
1236 if (char_code > String::kMaxAsciiCharCode) {
1237 return -1;
1238 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001239 return bad_char_occurrence[char_code];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001240 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001241 return bad_char_occurrence[char_code % kBMAlphabetSize];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001242}
1243
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001244// Restricted simplified Boyer-Moore string matching.
1245// Uses only the bad-shift table of Boyer-Moore and only uses it
1246// for the character compared to the last character of the needle.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001247template <typename schar, typename pchar>
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001248static int BoyerMooreHorsepool(Vector<const schar> subject,
1249 Vector<const pchar> pattern,
1250 int start_index,
1251 bool* complete) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001252 int n = subject.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001253 int m = pattern.length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00001254 // Only preprocess at most kBMMaxShift last characters of pattern.
1255 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256
ager@chromium.org7c537e22008-10-16 08:43:32 +00001257 BoyerMoorePopulateBadCharTable(pattern, start);
1258
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001259 int badness = -m; // How bad we are doing without a good-suffix table.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001260 int idx; // No matches found prior to this index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001261 pchar last_char = pattern[m - 1];
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001262 int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001263 // Perform search
1264 for (idx = start_index; idx <= n - m;) {
1265 int j = m - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001266 int c;
1267 while (last_char != (c = subject[idx + j])) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001268 int bc_occ = CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001269 int shift = j - bc_occ;
1270 idx += shift;
1271 badness += 1 - shift; // at most zero, so badness cannot increase.
1272 if (idx > n - m) {
1273 *complete = true;
1274 return -1;
1275 }
1276 }
1277 j--;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001278 while (j >= 0 && pattern[j] == (subject[idx + j])) j--;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001279 if (j < 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001280 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001281 return idx;
1282 } else {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001283 idx += last_char_shift;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001284 // Badness increases by the number of characters we have
1285 // checked, and decreases by the number of characters we
1286 // can skip by shifting. It's a measure of how we are doing
1287 // compared to reading each character exactly once.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001288 badness += (m - j) - last_char_shift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001289 if (badness > 0) {
1290 *complete = false;
1291 return idx;
1292 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001293 }
1294 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001295 *complete = true;
1296 return -1;
1297}
ager@chromium.org7c537e22008-10-16 08:43:32 +00001298
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001299
1300template <typename schar, typename pchar>
1301static int BoyerMooreIndexOf(Vector<const schar> subject,
1302 Vector<const pchar> pattern,
1303 int idx) {
1304 int n = subject.length();
1305 int m = pattern.length();
1306 // Only preprocess at most kBMMaxShift last characters of pattern.
1307 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
1308
1309 // Build the Good Suffix table and continue searching.
1310 BoyerMoorePopulateGoodSuffixTable(pattern, start);
1311 pchar last_char = pattern[m - 1];
1312 // Continue search from i.
1313 do {
1314 int j = m - 1;
1315 schar c;
1316 while (last_char != (c = subject[idx + j])) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001317 int shift = j - CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001318 idx += shift;
1319 if (idx > n - m) {
1320 return -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001321 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001322 }
1323 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1324 if (j < 0) {
1325 return idx;
1326 } else if (j < start) {
1327 // we have matched more than our tables allow us to be smart about.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001328 // Fall back on BMH shift.
1329 idx += m - 1 - CharOccurrence<schar, pchar>(last_char);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001330 } else {
1331 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001332 int bc_occ = CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001333 int shift = j - bc_occ; // Bad-char shift.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001334 if (gs_shift > shift) {
1335 shift = gs_shift;
1336 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001337 idx += shift;
1338 }
1339 } while (idx <= n - m);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001340
1341 return -1;
1342}
1343
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001344
1345template <typename schar>
ager@chromium.org7c537e22008-10-16 08:43:32 +00001346static int SingleCharIndexOf(Vector<const schar> string,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001347 schar pattern_char,
ager@chromium.org7c537e22008-10-16 08:43:32 +00001348 int start_index) {
1349 for (int i = start_index, n = string.length(); i < n; i++) {
1350 if (pattern_char == string[i]) {
1351 return i;
1352 }
1353 }
1354 return -1;
1355}
1356
1357// Trivial string search for shorter strings.
1358// On return, if "complete" is set to true, the return value is the
1359// final result of searching for the patter in the subject.
1360// If "complete" is set to false, the return value is the index where
1361// further checking should start, i.e., it's guaranteed that the pattern
1362// does not occur at a position prior to the returned index.
1363template <typename pchar, typename schar>
1364static int SimpleIndexOf(Vector<const schar> subject,
1365 Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001366 int idx,
1367 bool* complete) {
1368 // Badness is a count of how much work we have done. When we have
1369 // done enough work we decide it's probably worth switching to a better
1370 // algorithm.
1371 int badness = -10 - (pattern.length() << 2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001372 // We know our pattern is at least 2 characters, we cache the first so
1373 // the common case of the first character not matching is faster.
1374 pchar pattern_first_char = pattern[0];
1375
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001376 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1377 badness++;
1378 if (badness > 0) {
1379 *complete = false;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001380 return i;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001381 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001382 if (subject[i] != pattern_first_char) continue;
1383 int j = 1;
1384 do {
1385 if (pattern[j] != subject[i+j]) {
1386 break;
1387 }
1388 j++;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001389 } while (j < pattern.length());
1390 if (j == pattern.length()) {
1391 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001392 return i;
1393 }
1394 badness += j;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001395 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001396 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001397 return -1;
1398}
1399
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001400// Simple indexOf that never bails out. For short patterns only.
1401template <typename pchar, typename schar>
1402static int SimpleIndexOf(Vector<const schar> subject,
1403 Vector<const pchar> pattern,
1404 int idx) {
1405 pchar pattern_first_char = pattern[0];
1406 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1407 if (subject[i] != pattern_first_char) continue;
1408 int j = 1;
1409 do {
1410 if (pattern[j] != subject[i+j]) {
1411 break;
1412 }
1413 j++;
1414 } while (j < pattern.length());
1415 if (j == pattern.length()) {
1416 return i;
1417 }
1418 }
1419 return -1;
1420}
1421
1422
1423// Dispatch to different algorithms.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001424template <typename schar, typename pchar>
1425static int StringMatchStrategy(Vector<const schar> sub,
1426 Vector<const pchar> pat,
1427 int start_index) {
1428 ASSERT(pat.length() > 1);
1429
1430 // We have an ASCII haystack and a non-ASCII needle. Check if there
1431 // really is a non-ASCII character in the needle and bail out if there
1432 // is.
1433 if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
1434 for (int i = 0; i < pat.length(); i++) {
1435 uc16 c = pat[i];
1436 if (c > String::kMaxAsciiCharCode) {
1437 return -1;
1438 }
1439 }
1440 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001441 if (pat.length() < kBMMinPatternLength) {
1442 // We don't believe fancy searching can ever be more efficient.
1443 // The max shift of Boyer-Moore on a pattern of this length does
1444 // not compensate for the overhead.
1445 return SimpleIndexOf(sub, pat, start_index);
1446 }
1447 // Try algorithms in order of increasing setup cost and expected performance.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001448 bool complete;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001449 int idx = SimpleIndexOf(sub, pat, start_index, &complete);
1450 if (complete) return idx;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001451 idx = BoyerMooreHorsepool(sub, pat, idx, &complete);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001452 if (complete) return idx;
1453 return BoyerMooreIndexOf(sub, pat, idx);
1454}
1455
1456// Perform string match of pattern on subject, starting at start index.
1457// Caller must ensure that 0 <= start_index <= sub->length(),
1458// and should check that pat->length() + start_index <= sub->length()
1459int Runtime::StringMatch(Handle<String> sub,
1460 Handle<String> pat,
1461 int start_index) {
1462 ASSERT(0 <= start_index);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001463 StringShape sub_shape(*sub);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001464 ASSERT(start_index <= sub->length(sub_shape));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001465
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001466 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001467 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468
ager@chromium.org870a0b62008-11-04 11:43:05 +00001469 int subject_length = sub->length(sub_shape);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001470 if (start_index + pattern_length > subject_length) return -1;
1471
ager@chromium.org870a0b62008-11-04 11:43:05 +00001472 if (!sub->IsFlat(sub_shape)) {
1473 FlattenString(sub);
1474 sub_shape = StringShape(*sub);
1475 }
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001476 StringShape pat_shape(*pat);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 // Searching for one specific character is common. For one
ager@chromium.org7c537e22008-10-16 08:43:32 +00001478 // character patterns linear search is necessary, so any smart
1479 // algorithm is unnecessary overhead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 if (pattern_length == 1) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001481 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
ager@chromium.org870a0b62008-11-04 11:43:05 +00001482 if (sub_shape.IsAsciiRepresentation()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001483 uc16 pchar = pat->Get(pat_shape, 0);
1484 if (pchar > String::kMaxAsciiCharCode) {
1485 return -1;
1486 }
1487 Vector<const char> ascii_vector =
1488 sub->ToAsciiVector().SubVector(start_index, subject_length);
1489 const void* pos = memchr(ascii_vector.start(),
1490 static_cast<const char>(pchar),
1491 static_cast<size_t>(ascii_vector.length()));
1492 if (pos == NULL) {
1493 return -1;
1494 }
1495 return reinterpret_cast<const char*>(pos) - ascii_vector.start()
1496 + start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00001498 return SingleCharIndexOf(sub->ToUC16Vector(),
1499 pat->Get(pat_shape, 0),
1500 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 }
1502
ager@chromium.org870a0b62008-11-04 11:43:05 +00001503 if (!pat->IsFlat(pat_shape)) {
1504 FlattenString(pat);
1505 pat_shape = StringShape(*pat);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001506 sub_shape = StringShape(*sub);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001507 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001508
ager@chromium.org7c537e22008-10-16 08:43:32 +00001509 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1510 // dispatch on type of strings
ager@chromium.org870a0b62008-11-04 11:43:05 +00001511 if (pat_shape.IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001512 Vector<const char> pat_vector = pat->ToAsciiVector();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001513 if (sub_shape.IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001514 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001515 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001516 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001517 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001518 Vector<const uc16> pat_vector = pat->ToUC16Vector();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001519 if (sub_shape.IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001520 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001522 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001523}
1524
1525
1526static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001527 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001528 ASSERT(args.length() == 3);
1529
ager@chromium.org7c537e22008-10-16 08:43:32 +00001530 CONVERT_ARG_CHECKED(String, sub, 0);
1531 CONVERT_ARG_CHECKED(String, pat, 1);
1532
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001533 Object* index = args[2];
1534 uint32_t start_index;
1535 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1536
ager@chromium.org870a0b62008-11-04 11:43:05 +00001537 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001538 int position = Runtime::StringMatch(sub, pat, start_index);
1539 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540}
1541
1542
1543static Object* Runtime_StringLastIndexOf(Arguments args) {
1544 NoHandleAllocation ha;
1545 ASSERT(args.length() == 3);
1546
1547 CONVERT_CHECKED(String, sub, args[0]);
1548 CONVERT_CHECKED(String, pat, args[1]);
1549 Object* index = args[2];
1550
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001551 sub->TryFlattenIfNotFlat(StringShape(sub));
1552 pat->TryFlattenIfNotFlat(StringShape(pat));
ager@chromium.org870a0b62008-11-04 11:43:05 +00001553
1554 StringShape sub_shape(sub);
1555 StringShape pat_shape(pat);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556
1557 uint32_t start_index;
1558 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1559
ager@chromium.org870a0b62008-11-04 11:43:05 +00001560 uint32_t pattern_length = pat->length(pat_shape);
1561 uint32_t sub_length = sub->length(sub_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001563 if (start_index + pattern_length > sub_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 start_index = sub_length - pattern_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001565 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566
1567 for (int i = start_index; i >= 0; i--) {
1568 bool found = true;
1569 for (uint32_t j = 0; j < pattern_length; j++) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001570 if (sub->Get(sub_shape, i + j) != pat->Get(pat_shape, j)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 found = false;
1572 break;
1573 }
1574 }
1575 if (found) return Smi::FromInt(i);
1576 }
1577
1578 return Smi::FromInt(-1);
1579}
1580
1581
1582static Object* Runtime_StringLocaleCompare(Arguments args) {
1583 NoHandleAllocation ha;
1584 ASSERT(args.length() == 2);
1585
1586 CONVERT_CHECKED(String, str1, args[0]);
1587 CONVERT_CHECKED(String, str2, args[1]);
1588
1589 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.org870a0b62008-11-04 11:43:05 +00001590 StringShape shape1(str1);
1591 StringShape shape2(str2);
1592 int str1_length = str1->length(shape1);
1593 int str2_length = str2->length(shape2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594
1595 // Decide trivial cases without flattening.
1596 if (str1_length == 0) {
1597 if (str2_length == 0) return Smi::FromInt(0); // Equal.
1598 return Smi::FromInt(-str2_length);
1599 } else {
1600 if (str2_length == 0) return Smi::FromInt(str1_length);
1601 }
1602
1603 int end = str1_length < str2_length ? str1_length : str2_length;
1604
1605 // No need to flatten if we are going to find the answer on the first
1606 // character. At this point we know there is at least one character
1607 // in each string, due to the trivial case handling above.
ager@chromium.org870a0b62008-11-04 11:43:05 +00001608 int d = str1->Get(shape1, 0) - str2->Get(shape2, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001609 if (d != 0) return Smi::FromInt(d);
1610
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001611 str1->TryFlattenIfNotFlat(shape1); // Shapes are no longer valid now!
1612 str2->TryFlattenIfNotFlat(shape2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613
1614 static StringInputBuffer buf1;
1615 static StringInputBuffer buf2;
1616
1617 buf1.Reset(str1);
1618 buf2.Reset(str2);
1619
1620 for (int i = 0; i < end; i++) {
1621 uint16_t char1 = buf1.GetNext();
1622 uint16_t char2 = buf2.GetNext();
1623 if (char1 != char2) return Smi::FromInt(char1 - char2);
1624 }
1625
1626 return Smi::FromInt(str1_length - str2_length);
1627}
1628
1629
1630static Object* Runtime_StringSlice(Arguments args) {
1631 NoHandleAllocation ha;
1632 ASSERT(args.length() == 3);
1633
1634 CONVERT_CHECKED(String, value, args[0]);
1635 CONVERT_DOUBLE_CHECKED(from_number, args[1]);
1636 CONVERT_DOUBLE_CHECKED(to_number, args[2]);
1637
1638 int start = FastD2I(from_number);
1639 int end = FastD2I(to_number);
1640
1641 RUNTIME_ASSERT(end >= start);
1642 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001643 RUNTIME_ASSERT(end <= value->length());
1644 return value->Slice(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645}
1646
1647
1648static Object* Runtime_NumberToRadixString(Arguments args) {
1649 NoHandleAllocation ha;
1650 ASSERT(args.length() == 2);
1651
1652 CONVERT_DOUBLE_CHECKED(value, args[0]);
1653 if (isnan(value)) {
1654 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1655 }
1656 if (isinf(value)) {
1657 if (value < 0) {
1658 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1659 }
1660 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1661 }
1662 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
1663 int radix = FastD2I(radix_number);
1664 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1665 char* str = DoubleToRadixCString(value, radix);
1666 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
1667 DeleteArray(str);
1668 return result;
1669}
1670
1671
1672static Object* Runtime_NumberToFixed(Arguments args) {
1673 NoHandleAllocation ha;
1674 ASSERT(args.length() == 2);
1675
1676 CONVERT_DOUBLE_CHECKED(value, args[0]);
1677 if (isnan(value)) {
1678 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1679 }
1680 if (isinf(value)) {
1681 if (value < 0) {
1682 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1683 }
1684 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1685 }
1686 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1687 int f = FastD2I(f_number);
1688 RUNTIME_ASSERT(f >= 0);
1689 char* str = DoubleToFixedCString(value, f);
1690 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1691 DeleteArray(str);
1692 return res;
1693}
1694
1695
1696static Object* Runtime_NumberToExponential(Arguments args) {
1697 NoHandleAllocation ha;
1698 ASSERT(args.length() == 2);
1699
1700 CONVERT_DOUBLE_CHECKED(value, args[0]);
1701 if (isnan(value)) {
1702 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1703 }
1704 if (isinf(value)) {
1705 if (value < 0) {
1706 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1707 }
1708 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1709 }
1710 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1711 int f = FastD2I(f_number);
1712 RUNTIME_ASSERT(f >= -1 && f <= 20);
1713 char* str = DoubleToExponentialCString(value, f);
1714 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1715 DeleteArray(str);
1716 return res;
1717}
1718
1719
1720static Object* Runtime_NumberToPrecision(Arguments args) {
1721 NoHandleAllocation ha;
1722 ASSERT(args.length() == 2);
1723
1724 CONVERT_DOUBLE_CHECKED(value, args[0]);
1725 if (isnan(value)) {
1726 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1727 }
1728 if (isinf(value)) {
1729 if (value < 0) {
1730 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1731 }
1732 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1733 }
1734 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1735 int f = FastD2I(f_number);
1736 RUNTIME_ASSERT(f >= 1 && f <= 21);
1737 char* str = DoubleToPrecisionCString(value, f);
1738 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1739 DeleteArray(str);
1740 return res;
1741}
1742
1743
1744// Returns a single character string where first character equals
1745// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001746static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001747 StringShape shape(*string);
1748 if (index < static_cast<uint32_t>(string->length(shape))) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001749 string->TryFlattenIfNotFlat(shape); // Invalidates shape!
ager@chromium.org870a0b62008-11-04 11:43:05 +00001750 return LookupSingleCharacterStringFromCode(
1751 string->Get(StringShape(*string), index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001752 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001753 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754}
1755
1756
1757Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
1758 // Handle [] indexing on Strings
1759 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001760 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
1761 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001762 }
1763
1764 // Handle [] indexing on String objects
1765 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001766 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
1767 Handle<Object> result =
1768 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
1769 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001770 }
1771
1772 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001773 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001774 return prototype->GetElement(index);
1775 }
1776
1777 return object->GetElement(index);
1778}
1779
1780
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001781Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
1782 HandleScope scope;
1783
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001785 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001786 Handle<Object> error =
1787 Factory::NewTypeError("non_object_property_load",
1788 HandleVector(args, 2));
1789 return Top::Throw(*error);
1790 }
1791
1792 // Check if the given key is an array index.
1793 uint32_t index;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001794 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001795 return GetElementOrCharAt(object, index);
1796 }
1797
1798 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001799 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001800 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001801 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001802 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803 bool has_pending_exception = false;
1804 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001805 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001806 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808 }
1809
ager@chromium.org32912102009-01-16 10:38:43 +00001810 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001811 // the element if so.
1812 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813 return GetElementOrCharAt(object, index);
1814 } else {
1815 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001816 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 }
1818}
1819
1820
1821static Object* Runtime_GetProperty(Arguments args) {
1822 NoHandleAllocation ha;
1823 ASSERT(args.length() == 2);
1824
1825 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001826 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827
1828 return Runtime::GetObjectProperty(object, key);
1829}
1830
1831
ager@chromium.org7c537e22008-10-16 08:43:32 +00001832
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001833// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001834static Object* Runtime_KeyedGetProperty(Arguments args) {
1835 NoHandleAllocation ha;
1836 ASSERT(args.length() == 2);
1837
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001838 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00001839 // itself.
1840 //
1841 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00001842 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00001843 // global proxy object never has properties. This is the case
1844 // because the global proxy object forwards everything to its hidden
1845 // prototype including local lookups.
1846 //
1847 // Additionally, we need to make sure that we do not cache results
1848 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001849 if (args[0]->IsJSObject() &&
1850 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00001851 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001852 args[1]->IsString()) {
1853 JSObject* receiver = JSObject::cast(args[0]);
1854 String* key = String::cast(args[1]);
1855 if (receiver->HasFastProperties()) {
1856 // Attempt to use lookup cache.
1857 Object* obj = Heap::GetKeyedLookupCache();
1858 if (obj->IsFailure()) return obj;
1859 LookupCache* cache = LookupCache::cast(obj);
1860 Map* receiver_map = receiver->map();
1861 int offset = cache->Lookup(receiver_map, key);
1862 if (offset != LookupCache::kNotFound) {
1863 Object* value = receiver->FastPropertyAt(offset);
1864 return value->IsTheHole() ? Heap::undefined_value() : value;
1865 }
1866 // Lookup cache miss. Perform lookup and update the cache if
1867 // appropriate.
1868 LookupResult result;
1869 receiver->LocalLookup(key, &result);
1870 if (result.IsProperty() && result.IsLoaded() && result.type() == FIELD) {
1871 int offset = result.GetFieldIndex();
1872 Object* obj = cache->Put(receiver_map, key, offset);
1873 if (obj->IsFailure()) return obj;
1874 Heap::SetKeyedLookupCache(LookupCache::cast(obj));
1875 Object* value = receiver->FastPropertyAt(offset);
1876 return value->IsTheHole() ? Heap::undefined_value() : value;
1877 }
1878 } else {
1879 // Attempt dictionary lookup.
1880 Dictionary* dictionary = receiver->property_dictionary();
1881 int entry = dictionary->FindStringEntry(key);
1882 if ((entry != DescriptorArray::kNotFound) &&
1883 (dictionary->DetailsAt(entry).type() == NORMAL)) {
1884 return dictionary->ValueAt(entry);
1885 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001886 }
1887 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001888
1889 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001890 return Runtime::GetObjectProperty(args.at<Object>(0),
1891 args.at<Object>(1));
1892}
1893
1894
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001895Object* Runtime::SetObjectProperty(Handle<Object> object,
1896 Handle<Object> key,
1897 Handle<Object> value,
1898 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001899 HandleScope scope;
1900
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001902 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001903 Handle<Object> error =
1904 Factory::NewTypeError("non_object_property_store",
1905 HandleVector(args, 2));
1906 return Top::Throw(*error);
1907 }
1908
1909 // If the object isn't a JavaScript object, we ignore the store.
1910 if (!object->IsJSObject()) return *value;
1911
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001912 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
1913
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914 // Check if the given key is an array index.
1915 uint32_t index;
1916 if (Array::IndexFromObject(*key, &index)) {
1917 ASSERT(attr == NONE);
1918
1919 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
1920 // of a string using [] notation. We need to support this too in
1921 // JavaScript.
1922 // In the case of a String object we just need to redirect the assignment to
1923 // the underlying string if the index is in range. Since the underlying
1924 // string does nothing with the assignment then we can ignore such
1925 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001926 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001927 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001928 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001930 Handle<Object> result = SetElement(js_object, index, value);
1931 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 return *value;
1933 }
1934
1935 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001936 Handle<Object> result;
1937 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001938 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001939 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001940 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001941 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001942 key_string->TryFlattenIfNotFlat(StringShape(*key_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001943 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001944 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001945 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001946 return *value;
1947 }
1948
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 bool has_pending_exception = false;
1951 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
1952 if (has_pending_exception) return Failure::Exception();
1953 Handle<String> name = Handle<String>::cast(converted);
1954
1955 if (name->AsArrayIndex(&index)) {
1956 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001957 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001959 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 }
1961}
1962
1963
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001964static Object* Runtime_SetProperty(Arguments args) {
1965 NoHandleAllocation ha;
1966 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1967
1968 Handle<Object> object = args.at<Object>(0);
1969 Handle<Object> key = args.at<Object>(1);
1970 Handle<Object> value = args.at<Object>(2);
1971
1972 // Compute attributes.
1973 PropertyAttributes attributes = NONE;
1974 if (args.length() == 4) {
1975 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001976 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001977 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001978 RUNTIME_ASSERT(
1979 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1980 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001981 }
1982 return Runtime::SetObjectProperty(object, key, value, attributes);
1983}
1984
1985
1986// Set a local property, even if it is READ_ONLY. If the property does not
1987// exist, it will be added with attributes NONE.
1988static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
1989 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001990 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991 CONVERT_CHECKED(JSObject, object, args[0]);
1992 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001993 // Compute attributes.
1994 PropertyAttributes attributes = NONE;
1995 if (args.length() == 4) {
1996 CONVERT_CHECKED(Smi, value_obj, args[3]);
1997 int unchecked_value = value_obj->value();
1998 // Only attribute bits should be set.
1999 RUNTIME_ASSERT(
2000 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
2001 attributes = static_cast<PropertyAttributes>(unchecked_value);
2002 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002003
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002004 return object->
2005 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006}
2007
2008
2009static Object* Runtime_DeleteProperty(Arguments args) {
2010 NoHandleAllocation ha;
2011 ASSERT(args.length() == 2);
2012
2013 CONVERT_CHECKED(JSObject, object, args[0]);
2014 CONVERT_CHECKED(String, key, args[1]);
2015 return object->DeleteProperty(key);
2016}
2017
2018
2019static Object* Runtime_HasLocalProperty(Arguments args) {
2020 NoHandleAllocation ha;
2021 ASSERT(args.length() == 2);
2022 CONVERT_CHECKED(String, key, args[1]);
2023
2024 // Only JS objects can have properties.
2025 if (args[0]->IsJSObject()) {
2026 JSObject* object = JSObject::cast(args[0]);
2027 if (object->HasLocalProperty(key)) return Heap::true_value();
2028 } else if (args[0]->IsString()) {
2029 // Well, there is one exception: Handle [] on strings.
2030 uint32_t index;
2031 if (key->AsArrayIndex(&index)) {
2032 String* string = String::cast(args[0]);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002033 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 return Heap::true_value();
2035 }
2036 }
2037 return Heap::false_value();
2038}
2039
2040
2041static Object* Runtime_HasProperty(Arguments args) {
2042 NoHandleAllocation na;
2043 ASSERT(args.length() == 2);
2044
2045 // Only JS objects can have properties.
2046 if (args[0]->IsJSObject()) {
2047 JSObject* object = JSObject::cast(args[0]);
2048 CONVERT_CHECKED(String, key, args[1]);
2049 if (object->HasProperty(key)) return Heap::true_value();
2050 }
2051 return Heap::false_value();
2052}
2053
2054
2055static Object* Runtime_HasElement(Arguments args) {
2056 NoHandleAllocation na;
2057 ASSERT(args.length() == 2);
2058
2059 // Only JS objects can have elements.
2060 if (args[0]->IsJSObject()) {
2061 JSObject* object = JSObject::cast(args[0]);
2062 CONVERT_CHECKED(Smi, index_obj, args[1]);
2063 uint32_t index = index_obj->value();
2064 if (object->HasElement(index)) return Heap::true_value();
2065 }
2066 return Heap::false_value();
2067}
2068
2069
2070static Object* Runtime_IsPropertyEnumerable(Arguments args) {
2071 NoHandleAllocation ha;
2072 ASSERT(args.length() == 2);
2073
2074 CONVERT_CHECKED(JSObject, object, args[0]);
2075 CONVERT_CHECKED(String, key, args[1]);
2076
2077 uint32_t index;
2078 if (key->AsArrayIndex(&index)) {
2079 return Heap::ToBoolean(object->HasElement(index));
2080 }
2081
ager@chromium.org870a0b62008-11-04 11:43:05 +00002082 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
2083 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002084}
2085
2086
2087static Object* Runtime_GetPropertyNames(Arguments args) {
2088 HandleScope scope;
2089 ASSERT(args.length() == 1);
2090
2091 CONVERT_CHECKED(JSObject, raw_object, args[0]);
2092 Handle<JSObject> object(raw_object);
2093 return *GetKeysFor(object);
2094}
2095
2096
2097// Returns either a FixedArray as Runtime_GetPropertyNames,
2098// or, if the given object has an enum cache that contains
2099// all enumerable properties of the object and its prototypes
2100// have none, the map of the object. This is used to speed up
2101// the check for deletions during a for-in.
2102static Object* Runtime_GetPropertyNamesFast(Arguments args) {
2103 ASSERT(args.length() == 1);
2104
2105 CONVERT_CHECKED(JSObject, raw_object, args[0]);
2106
2107 if (raw_object->IsSimpleEnum()) return raw_object->map();
2108
2109 HandleScope scope;
2110 Handle<JSObject> object(raw_object);
2111 Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
2112
2113 // Test again, since cache may have been built by preceding call.
2114 if (object->IsSimpleEnum()) return object->map();
2115
2116 return *content;
2117}
2118
2119
2120static Object* Runtime_GetArgumentsProperty(Arguments args) {
2121 NoHandleAllocation ha;
2122 ASSERT(args.length() == 1);
2123
2124 // Compute the frame holding the arguments.
2125 JavaScriptFrameIterator it;
2126 it.AdvanceToArgumentsFrame();
2127 JavaScriptFrame* frame = it.frame();
2128
2129 // Get the actual number of provided arguments.
2130 const uint32_t n = frame->GetProvidedParametersCount();
2131
2132 // Try to convert the key to an index. If successful and within
2133 // index return the the argument from the frame.
2134 uint32_t index;
2135 if (Array::IndexFromObject(args[0], &index) && index < n) {
2136 return frame->GetParameter(index);
2137 }
2138
2139 // Convert the key to a string.
2140 HandleScope scope;
2141 bool exception = false;
2142 Handle<Object> converted =
2143 Execution::ToString(args.at<Object>(0), &exception);
2144 if (exception) return Failure::Exception();
2145 Handle<String> key = Handle<String>::cast(converted);
2146
2147 // Try to convert the string key into an array index.
2148 if (key->AsArrayIndex(&index)) {
2149 if (index < n) {
2150 return frame->GetParameter(index);
2151 } else {
2152 return Top::initial_object_prototype()->GetElement(index);
2153 }
2154 }
2155
2156 // Handle special arguments properties.
2157 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
2158 if (key->Equals(Heap::callee_symbol())) return frame->function();
2159
2160 // Lookup in the initial Object.prototype object.
2161 return Top::initial_object_prototype()->GetProperty(*key);
2162}
2163
2164
kasperl@chromium.org061ef742009-02-27 12:16:20 +00002165static Object* Runtime_ToFastProperties(Arguments args) {
2166 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00002167 Handle<Object> object = args.at<Object>(0);
2168 if (object->IsJSObject()) {
2169 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
2170 js_object->TransformToFastProperties(0);
2171 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00002172 return *object;
2173}
2174
2175
2176static Object* Runtime_ToSlowProperties(Arguments args) {
2177 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00002178 Handle<Object> object = args.at<Object>(0);
2179 if (object->IsJSObject()) {
2180 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
2181 js_object->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES);
2182 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00002183 return *object;
2184}
2185
2186
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002187static Object* Runtime_ToBool(Arguments args) {
2188 NoHandleAllocation ha;
2189 ASSERT(args.length() == 1);
2190
2191 return args[0]->ToBoolean();
2192}
2193
2194
2195// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
2196// Possible optimizations: put the type string into the oddballs.
2197static Object* Runtime_Typeof(Arguments args) {
2198 NoHandleAllocation ha;
2199
2200 Object* obj = args[0];
2201 if (obj->IsNumber()) return Heap::number_symbol();
2202 HeapObject* heap_obj = HeapObject::cast(obj);
2203
2204 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002205 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002206
2207 InstanceType instance_type = heap_obj->map()->instance_type();
2208 if (instance_type < FIRST_NONSTRING_TYPE) {
2209 return Heap::string_symbol();
2210 }
2211
2212 switch (instance_type) {
2213 case ODDBALL_TYPE:
2214 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
2215 return Heap::boolean_symbol();
2216 }
2217 if (heap_obj->IsNull()) {
2218 return Heap::object_symbol();
2219 }
2220 ASSERT(heap_obj->IsUndefined());
2221 return Heap::undefined_symbol();
2222 case JS_FUNCTION_TYPE:
2223 return Heap::function_symbol();
2224 default:
2225 // For any kind of object not handled above, the spec rule for
2226 // host objects gives that it is okay to return "object"
2227 return Heap::object_symbol();
2228 }
2229}
2230
2231
2232static Object* Runtime_StringToNumber(Arguments args) {
2233 NoHandleAllocation ha;
2234 ASSERT(args.length() == 1);
2235 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002236 subject->TryFlattenIfNotFlat(StringShape(subject));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002237 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
2238}
2239
2240
2241static Object* Runtime_StringFromCharCodeArray(Arguments args) {
2242 NoHandleAllocation ha;
2243 ASSERT(args.length() == 1);
2244
2245 CONVERT_CHECKED(JSArray, codes, args[0]);
2246 int length = Smi::cast(codes->length())->value();
2247
2248 // Check if the string can be ASCII.
2249 int i;
2250 for (i = 0; i < length; i++) {
2251 Object* element = codes->GetElement(i);
2252 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
2253 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
2254 break;
2255 }
2256
2257 Object* object = NULL;
2258 if (i == length) { // The string is ASCII.
2259 object = Heap::AllocateRawAsciiString(length);
2260 } else { // The string is not ASCII.
2261 object = Heap::AllocateRawTwoByteString(length);
2262 }
2263
2264 if (object->IsFailure()) return object;
2265 String* result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002266 StringShape result_shape(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002267 for (int i = 0; i < length; i++) {
2268 Object* element = codes->GetElement(i);
2269 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002270 result->Set(result_shape, i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002271 }
2272 return result;
2273}
2274
2275
2276// kNotEscaped is generated by the following:
2277//
2278// #!/bin/perl
2279// for (my $i = 0; $i < 256; $i++) {
2280// print "\n" if $i % 16 == 0;
2281// my $c = chr($i);
2282// my $escaped = 1;
2283// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
2284// print $escaped ? "0, " : "1, ";
2285// }
2286
2287
2288static bool IsNotEscaped(uint16_t character) {
2289 // Only for 8 bit characters, the rest are always escaped (in a different way)
2290 ASSERT(character < 256);
2291 static const char kNotEscaped[256] = {
2292 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2293 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2294 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
2295 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
2296 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2297 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
2298 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2299 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
2300 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2301 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2302 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2303 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2304 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2305 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2306 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2307 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2308 };
2309 return kNotEscaped[character] != 0;
2310}
2311
2312
2313static Object* Runtime_URIEscape(Arguments args) {
2314 const char hex_chars[] = "0123456789ABCDEF";
2315 NoHandleAllocation ha;
2316 ASSERT(args.length() == 1);
2317 CONVERT_CHECKED(String, source, args[0]);
2318
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002319 source->TryFlattenIfNotFlat(StringShape(source));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002320
2321 int escaped_length = 0;
2322 int length = source->length();
2323 {
2324 Access<StringInputBuffer> buffer(&string_input_buffer);
2325 buffer->Reset(source);
2326 while (buffer->has_more()) {
2327 uint16_t character = buffer->GetNext();
2328 if (character >= 256) {
2329 escaped_length += 6;
2330 } else if (IsNotEscaped(character)) {
2331 escaped_length++;
2332 } else {
2333 escaped_length += 3;
2334 }
2335 // We don't allow strings that are longer than Smi range.
2336 if (!Smi::IsValid(escaped_length)) {
2337 Top::context()->mark_out_of_memory();
2338 return Failure::OutOfMemoryException();
2339 }
2340 }
2341 }
2342 // No length change implies no change. Return original string if no change.
2343 if (escaped_length == length) {
2344 return source;
2345 }
2346 Object* o = Heap::AllocateRawAsciiString(escaped_length);
2347 if (o->IsFailure()) return o;
2348 String* destination = String::cast(o);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002349 StringShape dshape(destination);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002350 int dest_position = 0;
2351
2352 Access<StringInputBuffer> buffer(&string_input_buffer);
2353 buffer->Rewind();
2354 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002355 uint16_t chr = buffer->GetNext();
2356 if (chr >= 256) {
2357 destination->Set(dshape, dest_position, '%');
2358 destination->Set(dshape, dest_position+1, 'u');
2359 destination->Set(dshape, dest_position+2, hex_chars[chr >> 12]);
2360 destination->Set(dshape, dest_position+3, hex_chars[(chr >> 8) & 0xf]);
2361 destination->Set(dshape, dest_position+4, hex_chars[(chr >> 4) & 0xf]);
2362 destination->Set(dshape, dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002363 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002364 } else if (IsNotEscaped(chr)) {
2365 destination->Set(dshape, dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002366 dest_position++;
2367 } else {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002368 destination->Set(dshape, dest_position, '%');
2369 destination->Set(dshape, dest_position+1, hex_chars[chr >> 4]);
2370 destination->Set(dshape, dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002371 dest_position += 3;
2372 }
2373 }
2374 return destination;
2375}
2376
2377
2378static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
2379 static const signed char kHexValue['g'] = {
2380 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2381 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2382 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2383 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
2384 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2385 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2386 -1, 10, 11, 12, 13, 14, 15 };
2387
2388 if (character1 > 'f') return -1;
2389 int hi = kHexValue[character1];
2390 if (hi == -1) return -1;
2391 if (character2 > 'f') return -1;
2392 int lo = kHexValue[character2];
2393 if (lo == -1) return -1;
2394 return (hi << 4) + lo;
2395}
2396
2397
ager@chromium.org870a0b62008-11-04 11:43:05 +00002398static inline int Unescape(String* source,
2399 StringShape shape,
2400 int i,
2401 int length,
2402 int* step) {
2403 uint16_t character = source->Get(shape, i);
2404 int32_t hi = 0;
2405 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002406 if (character == '%' &&
2407 i <= length - 6 &&
ager@chromium.org870a0b62008-11-04 11:43:05 +00002408 source->Get(shape, i + 1) == 'u' &&
2409 (hi = TwoDigitHex(source->Get(shape, i + 2),
2410 source->Get(shape, i + 3))) != -1 &&
2411 (lo = TwoDigitHex(source->Get(shape, i + 4),
2412 source->Get(shape, i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002413 *step = 6;
2414 return (hi << 8) + lo;
2415 } else if (character == '%' &&
2416 i <= length - 3 &&
ager@chromium.org870a0b62008-11-04 11:43:05 +00002417 (lo = TwoDigitHex(source->Get(shape, i + 1),
2418 source->Get(shape, i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002419 *step = 3;
2420 return lo;
2421 } else {
2422 *step = 1;
2423 return character;
2424 }
2425}
2426
2427
2428static Object* Runtime_URIUnescape(Arguments args) {
2429 NoHandleAllocation ha;
2430 ASSERT(args.length() == 1);
2431 CONVERT_CHECKED(String, source, args[0]);
2432
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002433 source->TryFlattenIfNotFlat(StringShape(source));
ager@chromium.org870a0b62008-11-04 11:43:05 +00002434 StringShape source_shape(source);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002435
2436 bool ascii = true;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002437 int length = source->length(source_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002438
2439 int unescaped_length = 0;
2440 for (int i = 0; i < length; unescaped_length++) {
2441 int step;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002442 if (Unescape(source,
2443 source_shape,
2444 i,
2445 length,
2446 &step) >
2447 String::kMaxAsciiCharCode)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002448 ascii = false;
2449 i += step;
2450 }
2451
2452 // No length change implies no change. Return original string if no change.
2453 if (unescaped_length == length)
2454 return source;
2455
2456 Object* o = ascii ?
2457 Heap::AllocateRawAsciiString(unescaped_length) :
2458 Heap::AllocateRawTwoByteString(unescaped_length);
2459 if (o->IsFailure()) return o;
2460 String* destination = String::cast(o);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002461 StringShape destination_shape(destination);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002462
2463 int dest_position = 0;
2464 for (int i = 0; i < length; dest_position++) {
2465 int step;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002466 destination->Set(destination_shape,
2467 dest_position,
2468 Unescape(source, source_shape, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002469 i += step;
2470 }
2471 return destination;
2472}
2473
2474
2475static Object* Runtime_StringParseInt(Arguments args) {
2476 NoHandleAllocation ha;
2477
2478 CONVERT_CHECKED(String, s, args[0]);
2479 CONVERT_DOUBLE_CHECKED(n, args[1]);
2480 int radix = FastD2I(n);
2481
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002482 s->TryFlattenIfNotFlat(StringShape(s));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002483
ager@chromium.org870a0b62008-11-04 11:43:05 +00002484 StringShape shape(s);
2485
2486 int len = s->length(shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002487 int i;
2488
2489 // Skip leading white space.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002490 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(shape, i)); i++) ;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002491 if (i == len) return Heap::nan_value();
2492
2493 // Compute the sign (default to +).
2494 int sign = 1;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002495 if (s->Get(shape, i) == '-') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002496 sign = -1;
2497 i++;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002498 } else if (s->Get(shape, i) == '+') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002499 i++;
2500 }
2501
2502 // Compute the radix if 0.
2503 if (radix == 0) {
2504 radix = 10;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002505 if (i < len && s->Get(shape, i) == '0') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002506 radix = 8;
2507 if (i + 1 < len) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002508 int c = s->Get(shape, i + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002509 if (c == 'x' || c == 'X') {
2510 radix = 16;
2511 i += 2;
2512 }
2513 }
2514 }
2515 } else if (radix == 16) {
2516 // Allow 0x or 0X prefix if radix is 16.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002517 if (i + 1 < len && s->Get(shape, i) == '0') {
2518 int c = s->Get(shape, i + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002519 if (c == 'x' || c == 'X') i += 2;
2520 }
2521 }
2522
2523 RUNTIME_ASSERT(2 <= radix && radix <= 36);
2524 double value;
2525 int end_index = StringToInt(s, i, radix, &value);
2526 if (end_index != i) {
2527 return Heap::NumberFromDouble(sign * value);
2528 }
2529 return Heap::nan_value();
2530}
2531
2532
2533static Object* Runtime_StringParseFloat(Arguments args) {
2534 NoHandleAllocation ha;
2535 CONVERT_CHECKED(String, str, args[0]);
2536
2537 // ECMA-262 section 15.1.2.3, empty string is NaN
2538 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
2539
2540 // Create a number object from the value.
2541 return Heap::NumberFromDouble(value);
2542}
2543
2544
2545static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
2546static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
2547
2548
2549template <class Converter>
2550static Object* ConvertCase(Arguments args,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002551 unibrow::Mapping<Converter, 128>* mapping) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002552 NoHandleAllocation ha;
2553
2554 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002555 s->TryFlattenIfNotFlat(StringShape(s));
ager@chromium.org870a0b62008-11-04 11:43:05 +00002556 StringShape shape(s);
2557
2558 int raw_string_length = s->length(shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002559 // Assume that the string is not empty; we need this assumption later
2560 if (raw_string_length == 0) return s;
2561 int length = raw_string_length;
2562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002563
2564 // We try this twice, once with the assumption that the result is
2565 // no longer than the input and, if that assumption breaks, again
2566 // with the exact length. This is implemented using a goto back
2567 // to this label if we discover that the assumption doesn't hold.
2568 // I apologize sincerely for this and will give a vaffel-is to
mads.s.ager31e71382008-08-13 09:32:07 +00002569 // the first person who can implement it in a nicer way.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002570 try_convert:
2571
2572 // Allocate the resulting string.
2573 //
2574 // NOTE: This assumes that the upper/lower case of an ascii
2575 // character is also ascii. This is currently the case, but it
2576 // might break in the future if we implement more context and locale
2577 // dependent upper/lower conversions.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002578 Object* o = shape.IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002579 ? Heap::AllocateRawAsciiString(length)
2580 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002581 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002582 String* result = String::cast(o);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002583 StringShape result_shape(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002584 bool has_changed_character = false;
2585
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002586 // Convert all characters to upper case, assuming that they will fit
2587 // in the buffer
2588 Access<StringInputBuffer> buffer(&string_input_buffer);
2589 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002590 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002591 int i = 0;
2592 // We can assume that the string is not empty
2593 uc32 current = buffer->GetNext();
2594 while (i < length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002595 bool has_next = buffer->has_more();
2596 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002597 int char_length = mapping->get(current, next, chars);
2598 if (char_length == 0) {
2599 // The case conversion of this character is the character itself.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002600 result->Set(result_shape, i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002601 i++;
2602 } else if (char_length == 1) {
2603 // Common case: converting the letter resulted in one character.
2604 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002605 result->Set(result_shape, i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002606 has_changed_character = true;
2607 i++;
2608 } else if (length == raw_string_length) {
2609 // We've assumed that the result would be as long as the
2610 // input but here is a character that converts to several
2611 // characters. No matter, we calculate the exact length
2612 // of the result and try the whole thing again.
2613 //
2614 // Note that this leaves room for optimization. We could just
2615 // memcpy what we already have to the result string. Also,
2616 // the result string is the last object allocated we could
2617 // "realloc" it and probably, in the vast majority of cases,
2618 // extend the existing string to be able to hold the full
2619 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002620 int next_length = 0;
2621 if (has_next) {
2622 next_length = mapping->get(next, 0, chars);
2623 if (next_length == 0) next_length = 1;
2624 }
2625 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002626 while (buffer->has_more()) {
2627 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002628 // NOTE: we use 0 as the next character here because, while
2629 // the next character may affect what a character converts to,
2630 // it does not in any case affect the length of what it convert
2631 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002632 int char_length = mapping->get(current, 0, chars);
2633 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002634 current_length += char_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002635 }
2636 length = current_length;
2637 goto try_convert;
2638 } else {
2639 for (int j = 0; j < char_length; j++) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002640 result->Set(result_shape, i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002641 i++;
2642 }
2643 has_changed_character = true;
2644 }
2645 current = next;
2646 }
2647 if (has_changed_character) {
2648 return result;
2649 } else {
2650 // If we didn't actually change anything in doing the conversion
2651 // we simple return the result and let the converted string
2652 // become garbage; there is no reason to keep two identical strings
2653 // alive.
2654 return s;
2655 }
2656}
2657
2658
2659static Object* Runtime_StringToLowerCase(Arguments args) {
2660 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
2661}
2662
2663
2664static Object* Runtime_StringToUpperCase(Arguments args) {
2665 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
2666}
2667
2668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002669static Object* Runtime_NumberToString(Arguments args) {
2670 NoHandleAllocation ha;
2671 ASSERT(args.length() == 1);
2672
2673 Object* number = args[0];
2674 RUNTIME_ASSERT(number->IsNumber());
2675
2676 Object* cached = Heap::GetNumberStringCache(number);
2677 if (cached != Heap::undefined_value()) {
2678 return cached;
2679 }
2680
2681 char arr[100];
2682 Vector<char> buffer(arr, ARRAY_SIZE(arr));
2683 const char* str;
2684 if (number->IsSmi()) {
2685 int num = Smi::cast(number)->value();
2686 str = IntToCString(num, buffer);
2687 } else {
2688 double num = HeapNumber::cast(number)->value();
2689 str = DoubleToCString(num, buffer);
2690 }
2691 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2692
2693 if (!result->IsFailure()) {
2694 Heap::SetNumberStringCache(number, String::cast(result));
2695 }
2696 return result;
2697}
2698
2699
2700static Object* Runtime_NumberToInteger(Arguments args) {
2701 NoHandleAllocation ha;
2702 ASSERT(args.length() == 1);
2703
2704 Object* obj = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002705 if (obj->IsSmi()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002706 CONVERT_DOUBLE_CHECKED(number, obj);
2707 return Heap::NumberFromDouble(DoubleToInteger(number));
2708}
2709
2710
2711static Object* Runtime_NumberToJSUint32(Arguments args) {
2712 NoHandleAllocation ha;
2713 ASSERT(args.length() == 1);
2714
2715 Object* obj = args[0];
2716 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
2717 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
2718 return Heap::NumberFromUint32(number);
2719}
2720
2721
2722static Object* Runtime_NumberToJSInt32(Arguments args) {
2723 NoHandleAllocation ha;
2724 ASSERT(args.length() == 1);
2725
2726 Object* obj = args[0];
2727 if (obj->IsSmi()) return obj;
2728 CONVERT_DOUBLE_CHECKED(number, obj);
2729 return Heap::NumberFromInt32(DoubleToInt32(number));
2730}
2731
2732
ager@chromium.org870a0b62008-11-04 11:43:05 +00002733// Converts a Number to a Smi, if possible. Returns NaN if the number is not
2734// a small integer.
2735static Object* Runtime_NumberToSmi(Arguments args) {
2736 NoHandleAllocation ha;
2737 ASSERT(args.length() == 1);
2738
2739 Object* obj = args[0];
2740 if (obj->IsSmi()) {
2741 return obj;
2742 }
2743 if (obj->IsHeapNumber()) {
2744 double value = HeapNumber::cast(obj)->value();
2745 int int_value = FastD2I(value);
2746 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
2747 return Smi::FromInt(int_value);
2748 }
2749 }
2750 return Heap::nan_value();
2751}
2752
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002753static Object* Runtime_NumberAdd(Arguments args) {
2754 NoHandleAllocation ha;
2755 ASSERT(args.length() == 2);
2756
2757 CONVERT_DOUBLE_CHECKED(x, args[0]);
2758 CONVERT_DOUBLE_CHECKED(y, args[1]);
2759 return Heap::AllocateHeapNumber(x + y);
2760}
2761
2762
2763static Object* Runtime_NumberSub(Arguments args) {
2764 NoHandleAllocation ha;
2765 ASSERT(args.length() == 2);
2766
2767 CONVERT_DOUBLE_CHECKED(x, args[0]);
2768 CONVERT_DOUBLE_CHECKED(y, args[1]);
2769 return Heap::AllocateHeapNumber(x - y);
2770}
2771
2772
2773static Object* Runtime_NumberMul(Arguments args) {
2774 NoHandleAllocation ha;
2775 ASSERT(args.length() == 2);
2776
2777 CONVERT_DOUBLE_CHECKED(x, args[0]);
2778 CONVERT_DOUBLE_CHECKED(y, args[1]);
2779 return Heap::AllocateHeapNumber(x * y);
2780}
2781
2782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002783static Object* Runtime_NumberUnaryMinus(Arguments args) {
2784 NoHandleAllocation ha;
2785 ASSERT(args.length() == 1);
2786
2787 CONVERT_DOUBLE_CHECKED(x, args[0]);
2788 return Heap::AllocateHeapNumber(-x);
2789}
2790
2791
2792static Object* Runtime_NumberDiv(Arguments args) {
2793 NoHandleAllocation ha;
2794 ASSERT(args.length() == 2);
2795
2796 CONVERT_DOUBLE_CHECKED(x, args[0]);
2797 CONVERT_DOUBLE_CHECKED(y, args[1]);
2798 return Heap::NewNumberFromDouble(x / y);
2799}
2800
2801
2802static Object* Runtime_NumberMod(Arguments args) {
2803 NoHandleAllocation ha;
2804 ASSERT(args.length() == 2);
2805
2806 CONVERT_DOUBLE_CHECKED(x, args[0]);
2807 CONVERT_DOUBLE_CHECKED(y, args[1]);
2808
2809#ifdef WIN32
2810 // Workaround MS fmod bugs. ECMA-262 says:
2811 // dividend is finite and divisor is an infinity => result equals dividend
2812 // dividend is a zero and divisor is nonzero finite => result equals dividend
2813 if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
2814 !(x == 0 && (y != 0 && isfinite(y))))
2815#endif
2816 x = fmod(x, y);
2817 // NewNumberFromDouble may return a Smi instead of a Number object
2818 return Heap::NewNumberFromDouble(x);
2819}
2820
2821
2822static Object* Runtime_StringAdd(Arguments args) {
2823 NoHandleAllocation ha;
2824 ASSERT(args.length() == 2);
2825
2826 CONVERT_CHECKED(String, str1, args[0]);
2827 CONVERT_CHECKED(String, str2, args[1]);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002828 int len1 = str1->length();
2829 int len2 = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002830 if (len1 == 0) return str2;
2831 if (len2 == 0) return str1;
2832 int length_sum = len1 + len2;
2833 // Make sure that an out of memory exception is thrown if the length
2834 // of the new cons string is too large to fit in a Smi.
2835 if (length_sum > Smi::kMaxValue || length_sum < 0) {
2836 Top::context()->mark_out_of_memory();
2837 return Failure::OutOfMemoryException();
2838 }
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002839 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002840}
2841
2842
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002843template<typename sinkchar>
2844static inline void StringBuilderConcatHelper(String* special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00002845 StringShape special_shape,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002846 sinkchar* sink,
2847 FixedArray* fixed_array,
2848 int array_length) {
2849 int position = 0;
2850 for (int i = 0; i < array_length; i++) {
2851 Object* element = fixed_array->get(i);
2852 if (element->IsSmi()) {
2853 int len = Smi::cast(element)->value();
2854 int pos = len >> 11;
2855 len &= 0x7ff;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002856 String::WriteToFlat(special,
2857 special_shape,
2858 sink + position,
2859 pos,
2860 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002861 position += len;
2862 } else {
2863 String* string = String::cast(element);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002864 StringShape shape(string);
2865 int element_length = string->length(shape);
2866 String::WriteToFlat(string, shape, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002867 position += element_length;
2868 }
2869 }
2870}
2871
2872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873static Object* Runtime_StringBuilderConcat(Arguments args) {
2874 NoHandleAllocation ha;
2875 ASSERT(args.length() == 2);
2876 CONVERT_CHECKED(JSArray, array, args[0]);
2877 CONVERT_CHECKED(String, special, args[1]);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002878 StringShape special_shape(special);
2879 int special_length = special->length(special_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002880 Object* smi_array_length = array->length();
2881 if (!smi_array_length->IsSmi()) {
2882 Top::context()->mark_out_of_memory();
2883 return Failure::OutOfMemoryException();
2884 }
2885 int array_length = Smi::cast(smi_array_length)->value();
2886 if (!array->HasFastElements()) {
2887 return Top::Throw(Heap::illegal_argument_symbol());
2888 }
2889 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002890 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002892 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002893
2894 if (array_length == 0) {
2895 return Heap::empty_string();
2896 } else if (array_length == 1) {
2897 Object* first = fixed_array->get(0);
2898 if (first->IsString()) return first;
2899 }
2900
ager@chromium.org870a0b62008-11-04 11:43:05 +00002901 bool ascii = special_shape.IsAsciiRepresentation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002902 int position = 0;
2903 for (int i = 0; i < array_length; i++) {
2904 Object* elt = fixed_array->get(i);
2905 if (elt->IsSmi()) {
2906 int len = Smi::cast(elt)->value();
2907 int pos = len >> 11;
2908 len &= 0x7ff;
2909 if (pos + len > special_length) {
2910 return Top::Throw(Heap::illegal_argument_symbol());
2911 }
2912 position += len;
2913 } else if (elt->IsString()) {
2914 String* element = String::cast(elt);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002915 StringShape element_shape(element);
2916 int element_length = element->length(element_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002917 if (!Smi::IsValid(element_length + position)) {
2918 Top::context()->mark_out_of_memory();
2919 return Failure::OutOfMemoryException();
2920 }
2921 position += element_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002922 if (ascii && !element_shape.IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002923 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002924 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002925 } else {
2926 return Top::Throw(Heap::illegal_argument_symbol());
2927 }
2928 }
2929
2930 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002931 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002933 if (ascii) {
2934 object = Heap::AllocateRawAsciiString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002935 if (object->IsFailure()) return object;
2936 SeqAsciiString* answer = SeqAsciiString::cast(object);
2937 StringBuilderConcatHelper(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00002938 special_shape,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002939 answer->GetChars(),
2940 fixed_array,
2941 array_length);
2942 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002943 } else {
2944 object = Heap::AllocateRawTwoByteString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002945 if (object->IsFailure()) return object;
2946 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
2947 StringBuilderConcatHelper(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00002948 special_shape,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002949 answer->GetChars(),
2950 fixed_array,
2951 array_length);
2952 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002953 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002954}
2955
2956
2957static Object* Runtime_NumberOr(Arguments args) {
2958 NoHandleAllocation ha;
2959 ASSERT(args.length() == 2);
2960
2961 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2962 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2963 return Heap::NumberFromInt32(x | y);
2964}
2965
2966
2967static Object* Runtime_NumberAnd(Arguments args) {
2968 NoHandleAllocation ha;
2969 ASSERT(args.length() == 2);
2970
2971 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2972 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2973 return Heap::NumberFromInt32(x & y);
2974}
2975
2976
2977static Object* Runtime_NumberXor(Arguments args) {
2978 NoHandleAllocation ha;
2979 ASSERT(args.length() == 2);
2980
2981 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2982 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2983 return Heap::NumberFromInt32(x ^ y);
2984}
2985
2986
2987static Object* Runtime_NumberNot(Arguments args) {
2988 NoHandleAllocation ha;
2989 ASSERT(args.length() == 1);
2990
2991 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2992 return Heap::NumberFromInt32(~x);
2993}
2994
2995
2996static Object* Runtime_NumberShl(Arguments args) {
2997 NoHandleAllocation ha;
2998 ASSERT(args.length() == 2);
2999
3000 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
3001 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
3002 return Heap::NumberFromInt32(x << (y & 0x1f));
3003}
3004
3005
3006static Object* Runtime_NumberShr(Arguments args) {
3007 NoHandleAllocation ha;
3008 ASSERT(args.length() == 2);
3009
3010 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
3011 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
3012 return Heap::NumberFromUint32(x >> (y & 0x1f));
3013}
3014
3015
3016static Object* Runtime_NumberSar(Arguments args) {
3017 NoHandleAllocation ha;
3018 ASSERT(args.length() == 2);
3019
3020 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
3021 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
3022 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
3023}
3024
3025
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003026static Object* Runtime_NumberEquals(Arguments args) {
3027 NoHandleAllocation ha;
3028 ASSERT(args.length() == 2);
3029
3030 CONVERT_DOUBLE_CHECKED(x, args[0]);
3031 CONVERT_DOUBLE_CHECKED(y, args[1]);
3032 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
3033 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
3034 if (x == y) return Smi::FromInt(EQUAL);
3035 Object* result;
3036 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
3037 result = Smi::FromInt(EQUAL);
3038 } else {
3039 result = Smi::FromInt(NOT_EQUAL);
3040 }
3041 return result;
3042}
3043
3044
3045static Object* Runtime_StringEquals(Arguments args) {
3046 NoHandleAllocation ha;
3047 ASSERT(args.length() == 2);
3048
3049 CONVERT_CHECKED(String, x, args[0]);
3050 CONVERT_CHECKED(String, y, args[1]);
3051
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003052 bool not_equal = !x->Equals(y);
3053 // This is slightly convoluted because the value that signifies
3054 // equality is 0 and inequality is 1 so we have to negate the result
3055 // from String::Equals.
3056 ASSERT(not_equal == 0 || not_equal == 1);
3057 STATIC_CHECK(EQUAL == 0);
3058 STATIC_CHECK(NOT_EQUAL == 1);
3059 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003060}
3061
3062
3063static Object* Runtime_NumberCompare(Arguments args) {
3064 NoHandleAllocation ha;
3065 ASSERT(args.length() == 3);
3066
3067 CONVERT_DOUBLE_CHECKED(x, args[0]);
3068 CONVERT_DOUBLE_CHECKED(y, args[1]);
3069 if (isnan(x) || isnan(y)) return args[2];
3070 if (x == y) return Smi::FromInt(EQUAL);
3071 if (isless(x, y)) return Smi::FromInt(LESS);
3072 return Smi::FromInt(GREATER);
3073}
3074
3075
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003076// Compare two Smis as if they were converted to strings and then
3077// compared lexicographically.
3078static Object* Runtime_SmiLexicographicCompare(Arguments args) {
3079 NoHandleAllocation ha;
3080 ASSERT(args.length() == 2);
3081
3082 // Arrays for the individual characters of the two Smis. Smis are
3083 // 31 bit integers and 10 decimal digits are therefore enough.
3084 static int x_elms[10];
3085 static int y_elms[10];
3086
3087 // Extract the integer values from the Smis.
3088 CONVERT_CHECKED(Smi, x, args[0]);
3089 CONVERT_CHECKED(Smi, y, args[1]);
3090 int x_value = x->value();
3091 int y_value = y->value();
3092
3093 // If the integers are equal so are the string representations.
3094 if (x_value == y_value) return Smi::FromInt(EQUAL);
3095
3096 // If one of the integers are zero the normal integer order is the
3097 // same as the lexicographic order of the string representations.
3098 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
3099
ager@chromium.org32912102009-01-16 10:38:43 +00003100 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003101 // smallest because the char code of '-' is less than the char code
3102 // of any digit. Otherwise, we make both values positive.
3103 if (x_value < 0 || y_value < 0) {
3104 if (y_value >= 0) return Smi::FromInt(LESS);
3105 if (x_value >= 0) return Smi::FromInt(GREATER);
3106 x_value = -x_value;
3107 y_value = -y_value;
3108 }
3109
3110 // Convert the integers to arrays of their decimal digits.
3111 int x_index = 0;
3112 int y_index = 0;
3113 while (x_value > 0) {
3114 x_elms[x_index++] = x_value % 10;
3115 x_value /= 10;
3116 }
3117 while (y_value > 0) {
3118 y_elms[y_index++] = y_value % 10;
3119 y_value /= 10;
3120 }
3121
3122 // Loop through the arrays of decimal digits finding the first place
3123 // where they differ.
3124 while (--x_index >= 0 && --y_index >= 0) {
3125 int diff = x_elms[x_index] - y_elms[y_index];
3126 if (diff != 0) return Smi::FromInt(diff);
3127 }
3128
3129 // If one array is a suffix of the other array, the longest array is
3130 // the representation of the largest of the Smis in the
3131 // lexicographic ordering.
3132 return Smi::FromInt(x_index - y_index);
3133}
3134
3135
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003136static Object* Runtime_StringCompare(Arguments args) {
3137 NoHandleAllocation ha;
3138 ASSERT(args.length() == 2);
3139
3140 CONVERT_CHECKED(String, x, args[0]);
3141 CONVERT_CHECKED(String, y, args[1]);
3142
ager@chromium.org870a0b62008-11-04 11:43:05 +00003143 StringShape x_shape(x);
3144 StringShape y_shape(y);
3145
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003146 // A few fast case tests before we flatten.
3147 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003148 if (y->length(y_shape) == 0) {
3149 if (x->length(x_shape) == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003150 return Smi::FromInt(GREATER);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003151 } else if (x->length(x_shape) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003152 return Smi::FromInt(LESS);
3153 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003154
ager@chromium.org870a0b62008-11-04 11:43:05 +00003155 int d = x->Get(x_shape, 0) - y->Get(y_shape, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003156 if (d < 0) return Smi::FromInt(LESS);
3157 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003158
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003159 x->TryFlattenIfNotFlat(x_shape); // Shapes are no longer valid!
3160 y->TryFlattenIfNotFlat(y_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003161
3162 static StringInputBuffer bufx;
3163 static StringInputBuffer bufy;
3164 bufx.Reset(x);
3165 bufy.Reset(y);
3166 while (bufx.has_more() && bufy.has_more()) {
3167 int d = bufx.GetNext() - bufy.GetNext();
3168 if (d < 0) return Smi::FromInt(LESS);
3169 else if (d > 0) return Smi::FromInt(GREATER);
3170 }
3171
3172 // x is (non-trivial) prefix of y:
3173 if (bufy.has_more()) return Smi::FromInt(LESS);
3174 // y is prefix of x:
3175 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
3176}
3177
3178
3179static Object* Runtime_Math_abs(Arguments args) {
3180 NoHandleAllocation ha;
3181 ASSERT(args.length() == 1);
3182
3183 CONVERT_DOUBLE_CHECKED(x, args[0]);
3184 return Heap::AllocateHeapNumber(fabs(x));
3185}
3186
3187
3188static Object* Runtime_Math_acos(Arguments args) {
3189 NoHandleAllocation ha;
3190 ASSERT(args.length() == 1);
3191
3192 CONVERT_DOUBLE_CHECKED(x, args[0]);
3193 return Heap::AllocateHeapNumber(acos(x));
3194}
3195
3196
3197static Object* Runtime_Math_asin(Arguments args) {
3198 NoHandleAllocation ha;
3199 ASSERT(args.length() == 1);
3200
3201 CONVERT_DOUBLE_CHECKED(x, args[0]);
3202 return Heap::AllocateHeapNumber(asin(x));
3203}
3204
3205
3206static Object* Runtime_Math_atan(Arguments args) {
3207 NoHandleAllocation ha;
3208 ASSERT(args.length() == 1);
3209
3210 CONVERT_DOUBLE_CHECKED(x, args[0]);
3211 return Heap::AllocateHeapNumber(atan(x));
3212}
3213
3214
3215static Object* Runtime_Math_atan2(Arguments args) {
3216 NoHandleAllocation ha;
3217 ASSERT(args.length() == 2);
3218
3219 CONVERT_DOUBLE_CHECKED(x, args[0]);
3220 CONVERT_DOUBLE_CHECKED(y, args[1]);
3221 double result;
3222 if (isinf(x) && isinf(y)) {
3223 // Make sure that the result in case of two infinite arguments
3224 // is a multiple of Pi / 4. The sign of the result is determined
3225 // by the first argument (x) and the sign of the second argument
3226 // determines the multiplier: one or three.
3227 static double kPiDividedBy4 = 0.78539816339744830962;
3228 int multiplier = (x < 0) ? -1 : 1;
3229 if (y < 0) multiplier *= 3;
3230 result = multiplier * kPiDividedBy4;
3231 } else {
3232 result = atan2(x, y);
3233 }
3234 return Heap::AllocateHeapNumber(result);
3235}
3236
3237
3238static Object* Runtime_Math_ceil(Arguments args) {
3239 NoHandleAllocation ha;
3240 ASSERT(args.length() == 1);
3241
3242 CONVERT_DOUBLE_CHECKED(x, args[0]);
3243 return Heap::NumberFromDouble(ceiling(x));
3244}
3245
3246
3247static Object* Runtime_Math_cos(Arguments args) {
3248 NoHandleAllocation ha;
3249 ASSERT(args.length() == 1);
3250
3251 CONVERT_DOUBLE_CHECKED(x, args[0]);
3252 return Heap::AllocateHeapNumber(cos(x));
3253}
3254
3255
3256static Object* Runtime_Math_exp(Arguments args) {
3257 NoHandleAllocation ha;
3258 ASSERT(args.length() == 1);
3259
3260 CONVERT_DOUBLE_CHECKED(x, args[0]);
3261 return Heap::AllocateHeapNumber(exp(x));
3262}
3263
3264
3265static Object* Runtime_Math_floor(Arguments args) {
3266 NoHandleAllocation ha;
3267 ASSERT(args.length() == 1);
3268
3269 CONVERT_DOUBLE_CHECKED(x, args[0]);
3270 return Heap::NumberFromDouble(floor(x));
3271}
3272
3273
3274static Object* Runtime_Math_log(Arguments args) {
3275 NoHandleAllocation ha;
3276 ASSERT(args.length() == 1);
3277
3278 CONVERT_DOUBLE_CHECKED(x, args[0]);
3279 return Heap::AllocateHeapNumber(log(x));
3280}
3281
3282
3283static Object* Runtime_Math_pow(Arguments args) {
3284 NoHandleAllocation ha;
3285 ASSERT(args.length() == 2);
3286
3287 CONVERT_DOUBLE_CHECKED(x, args[0]);
3288 CONVERT_DOUBLE_CHECKED(y, args[1]);
3289 if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
3290 return Heap::nan_value();
3291 } else if (y == 0) {
3292 return Smi::FromInt(1);
3293 } else {
3294 return Heap::AllocateHeapNumber(pow(x, y));
3295 }
3296}
3297
3298// Returns a number value with positive sign, greater than or equal to
3299// 0 but less than 1, chosen randomly.
mads.s.ager31e71382008-08-13 09:32:07 +00003300static Object* Runtime_Math_random(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003301 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003302 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003303
3304 // To get much better precision, we combine the results of two
3305 // invocations of random(). The result is computed by normalizing a
3306 // double in the range [0, RAND_MAX + 1) obtained by adding the
3307 // high-order bits in the range [0, RAND_MAX] with the low-order
3308 // bits in the range [0, 1).
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003309 double lo = static_cast<double>(random()) * (1.0 / (RAND_MAX + 1.0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003310 double hi = static_cast<double>(random());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003311 double result = (hi + lo) * (1.0 / (RAND_MAX + 1.0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003312 ASSERT(result >= 0 && result < 1);
3313 return Heap::AllocateHeapNumber(result);
3314}
3315
3316
3317static Object* Runtime_Math_round(Arguments args) {
3318 NoHandleAllocation ha;
3319 ASSERT(args.length() == 1);
3320
3321 CONVERT_DOUBLE_CHECKED(x, args[0]);
3322 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
3323 return Heap::NumberFromDouble(floor(x + 0.5));
3324}
3325
3326
3327static Object* Runtime_Math_sin(Arguments args) {
3328 NoHandleAllocation ha;
3329 ASSERT(args.length() == 1);
3330
3331 CONVERT_DOUBLE_CHECKED(x, args[0]);
3332 return Heap::AllocateHeapNumber(sin(x));
3333}
3334
3335
3336static Object* Runtime_Math_sqrt(Arguments args) {
3337 NoHandleAllocation ha;
3338 ASSERT(args.length() == 1);
3339
3340 CONVERT_DOUBLE_CHECKED(x, args[0]);
3341 return Heap::AllocateHeapNumber(sqrt(x));
3342}
3343
3344
3345static Object* Runtime_Math_tan(Arguments args) {
3346 NoHandleAllocation ha;
3347 ASSERT(args.length() == 1);
3348
3349 CONVERT_DOUBLE_CHECKED(x, args[0]);
3350 return Heap::AllocateHeapNumber(tan(x));
3351}
3352
3353
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003354// The NewArguments function is only used when constructing the
3355// arguments array when calling non-functions from JavaScript in
3356// runtime.js:CALL_NON_FUNCTION.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003357static Object* Runtime_NewArguments(Arguments args) {
3358 NoHandleAllocation ha;
3359 ASSERT(args.length() == 1);
3360
3361 // ECMA-262, 3rd., 10.1.8, p.39
3362 CONVERT_CHECKED(JSFunction, callee, args[0]);
3363
3364 // Compute the frame holding the arguments.
3365 JavaScriptFrameIterator it;
3366 it.AdvanceToArgumentsFrame();
3367 JavaScriptFrame* frame = it.frame();
3368
3369 const int length = frame->GetProvidedParametersCount();
3370 Object* result = Heap::AllocateArgumentsObject(callee, length);
3371 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003372 if (length > 0) {
3373 Object* obj = Heap::AllocateFixedArray(length);
3374 if (obj->IsFailure()) return obj;
3375 FixedArray* array = FixedArray::cast(obj);
3376 ASSERT(array->length() == length);
3377 WriteBarrierMode mode = array->GetWriteBarrierMode();
3378 for (int i = 0; i < length; i++) {
3379 array->set(i, frame->GetParameter(i), mode);
3380 }
3381 JSObject::cast(result)->set_elements(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003382 }
3383 return result;
3384}
3385
3386
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003387static Object* Runtime_NewArgumentsFast(Arguments args) {
3388 NoHandleAllocation ha;
3389 ASSERT(args.length() == 3);
3390
3391 JSFunction* callee = JSFunction::cast(args[0]);
3392 Object** parameters = reinterpret_cast<Object**>(args[1]);
3393 const int length = Smi::cast(args[2])->value();
3394
3395 Object* result = Heap::AllocateArgumentsObject(callee, length);
3396 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003397 ASSERT(Heap::InNewSpace(result));
3398
3399 // Allocate the elements if needed.
3400 if (length > 0) {
3401 // Allocate the fixed array.
3402 Object* obj = Heap::AllocateRawFixedArray(length);
3403 if (obj->IsFailure()) return obj;
3404 reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map());
3405 FixedArray* array = FixedArray::cast(obj);
3406 array->set_length(length);
3407 WriteBarrierMode mode = array->GetWriteBarrierMode();
3408 for (int i = 0; i < length; i++) {
3409 array->set(i, *--parameters, mode);
3410 }
3411 JSObject::cast(result)->set_elements(FixedArray::cast(obj),
3412 SKIP_WRITE_BARRIER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003413 }
3414 return result;
3415}
3416
3417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003418static Object* Runtime_NewClosure(Arguments args) {
3419 HandleScope scope;
3420 ASSERT(args.length() == 2);
3421 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
3422 CONVERT_ARG_CHECKED(Context, context, 1);
3423
3424 Handle<JSFunction> result =
3425 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3426 return *result;
3427}
3428
3429
3430static Object* Runtime_NewObject(Arguments args) {
3431 NoHandleAllocation ha;
3432 ASSERT(args.length() == 1);
3433
3434 Object* constructor = args[0];
3435 if (constructor->IsJSFunction()) {
3436 JSFunction* function = JSFunction::cast(constructor);
3437
ager@chromium.org32912102009-01-16 10:38:43 +00003438 // Handle stepping into constructors if step into is active.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439 if (Debug::StepInActive()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003440 HandleScope scope;
3441 Debug::HandleStepIn(Handle<JSFunction>(function), 0, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003442 }
3443
3444 if (function->has_initial_map() &&
3445 function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
3446 // The 'Function' function ignores the receiver object when
3447 // called using 'new' and creates a new JSFunction object that
3448 // is returned. The receiver object is only used for error
3449 // reporting if an error occurs when constructing the new
3450 // JSFunction. AllocateJSObject should not be used to allocate
3451 // JSFunctions since it does not properly initialize the shared
3452 // part of the function. Since the receiver is ignored anyway,
3453 // we use the global object as the receiver instead of a new
3454 // JSFunction object. This way, errors are reported the same
3455 // way whether or not 'Function' is called using 'new'.
3456 return Top::context()->global();
3457 }
3458 return Heap::AllocateJSObject(function);
3459 }
3460
3461 HandleScope scope;
3462 Handle<Object> cons(constructor);
3463 // The constructor is not a function; throw a type error.
3464 Handle<Object> type_error =
3465 Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
3466 return Top::Throw(*type_error);
3467}
3468
3469
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003470static Object* Runtime_LazyCompile(Arguments args) {
3471 HandleScope scope;
3472 ASSERT(args.length() == 1);
3473
3474 Handle<JSFunction> function = args.at<JSFunction>(0);
3475#ifdef DEBUG
3476 if (FLAG_trace_lazy) {
3477 PrintF("[lazy: ");
3478 function->shared()->name()->Print();
3479 PrintF("]\n");
3480 }
3481#endif
3482
3483 // Compile the target function.
3484 ASSERT(!function->is_compiled());
3485 if (!CompileLazy(function, KEEP_EXCEPTION)) {
3486 return Failure::Exception();
3487 }
3488
3489 return function->code();
3490}
3491
3492
3493static Object* Runtime_GetCalledFunction(Arguments args) {
3494 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00003495 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003496 StackFrameIterator it;
3497 // Get past the JS-to-C exit frame.
3498 ASSERT(it.frame()->is_exit());
3499 it.Advance();
3500 // Get past the CALL_NON_FUNCTION activation frame.
3501 ASSERT(it.frame()->is_java_script());
3502 it.Advance();
3503 // Argument adaptor frames do not copy the function; we have to skip
3504 // past them to get to the real calling frame.
3505 if (it.frame()->is_arguments_adaptor()) it.Advance();
3506 // Get the function from the top of the expression stack of the
3507 // calling frame.
3508 StandardFrame* frame = StandardFrame::cast(it.frame());
3509 int index = frame->ComputeExpressionsCount() - 1;
3510 Object* result = frame->GetExpression(index);
3511 return result;
3512}
3513
3514
3515static Object* Runtime_GetFunctionDelegate(Arguments args) {
3516 HandleScope scope;
3517 ASSERT(args.length() == 1);
3518 RUNTIME_ASSERT(!args[0]->IsJSFunction());
3519 return *Execution::GetFunctionDelegate(args.at<Object>(0));
3520}
3521
3522
3523static Object* Runtime_NewContext(Arguments args) {
3524 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003525 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003526
kasper.lund7276f142008-07-30 08:49:36 +00003527 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003528 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
3529 Object* result = Heap::AllocateFunctionContext(length, function);
3530 if (result->IsFailure()) return result;
3531
3532 Top::set_context(Context::cast(result));
3533
kasper.lund7276f142008-07-30 08:49:36 +00003534 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003535}
3536
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003537static Object* PushContextHelper(Object* object, bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003539 Object* js_object = object;
3540 if (!js_object->IsJSObject()) {
3541 js_object = js_object->ToObject();
3542 if (js_object->IsFailure()) {
3543 if (!Failure::cast(js_object)->IsInternalError()) return js_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003544 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003545 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546 Handle<Object> result =
3547 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
3548 return Top::Throw(*result);
3549 }
3550 }
3551
3552 Object* result =
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003553 Heap::AllocateWithContext(Top::context(),
3554 JSObject::cast(js_object),
3555 is_catch_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003556 if (result->IsFailure()) return result;
3557
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003558 Context* context = Context::cast(result);
3559 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003560
kasper.lund7276f142008-07-30 08:49:36 +00003561 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003562}
3563
3564
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003565static Object* Runtime_PushContext(Arguments args) {
3566 NoHandleAllocation ha;
3567 ASSERT(args.length() == 1);
3568 return PushContextHelper(args[0], false);
3569}
3570
3571
3572static Object* Runtime_PushCatchContext(Arguments args) {
3573 NoHandleAllocation ha;
3574 ASSERT(args.length() == 1);
3575 return PushContextHelper(args[0], true);
3576}
3577
3578
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579static Object* Runtime_LookupContext(Arguments args) {
3580 HandleScope scope;
3581 ASSERT(args.length() == 2);
3582
3583 CONVERT_ARG_CHECKED(Context, context, 0);
3584 CONVERT_ARG_CHECKED(String, name, 1);
3585
3586 int index;
3587 PropertyAttributes attributes;
3588 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003589 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590 context->Lookup(name, flags, &index, &attributes);
3591
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003592 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003593 ASSERT(holder->IsJSObject());
3594 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 }
3596
3597 // No intermediate context found. Use global object by default.
3598 return Top::context()->global();
3599}
3600
3601
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003602// A mechanism to return pairs of Object*'s. This is somewhat
3603// compiler-dependent as it assumes that a 64-bit value (a long long)
3604// is returned via two registers (edx:eax on ia32). Both the ia32 and
3605// arm platform support this; it is mostly an issue of "coaxing" the
3606// compiler to do the right thing.
3607//
3608// TODO(1236026): This is a non-portable hack that should be removed.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003609typedef uint64_t ObjectPair;
3610static inline ObjectPair MakePair(Object* x, Object* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003612 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003613}
3614
3615
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003616static inline Object* Unhole(Object* x, PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
3618 USE(attributes);
3619 return x->IsTheHole() ? Heap::undefined_value() : x;
3620}
3621
3622
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003623static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
3624 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003625 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003626 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003627 JSFunction* context_extension_function =
3628 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003629 // If the holder isn't a context extension object, we just return it
3630 // as the receiver. This allows arguments objects to be used as
3631 // receivers, but only if they are put in the context scope chain
3632 // explicitly via a with-statement.
3633 Object* constructor = holder->map()->constructor();
3634 if (constructor != context_extension_function) return holder;
3635 // Fall back to using the global object as the receiver if the
3636 // property turns out to be a local variable allocated in a context
3637 // extension object - introduced via eval.
3638 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003639}
3640
3641
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003642static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643 HandleScope scope;
3644 ASSERT(args.length() == 2);
3645
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003646 if (!args[0]->IsContext() || !args[1]->IsString()) {
3647 return MakePair(IllegalOperation(), NULL);
3648 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003650 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003651
3652 int index;
3653 PropertyAttributes attributes;
3654 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003655 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003656 context->Lookup(name, flags, &index, &attributes);
3657
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003658 // If the index is non-negative, the slot has been found in a local
3659 // variable or a parameter. Read it from the context object or the
3660 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003662 // If the "property" we were looking for is a local variable or an
3663 // argument in a context, the receiver is the global object; see
3664 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
3665 JSObject* receiver = Top::context()->global()->global_receiver();
3666 Object* value = (holder->IsContext())
3667 ? Context::cast(*holder)->get(index)
3668 : JSObject::cast(*holder)->GetElement(index);
3669 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670 }
3671
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003672 // If the holder is found, we read the property from it.
3673 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00003674 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003675 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003676 JSObject* receiver;
3677 if (object->IsGlobalObject()) {
3678 receiver = GlobalObject::cast(object)->global_receiver();
3679 } else if (context->is_exception_holder(*holder)) {
3680 receiver = Top::context()->global()->global_receiver();
3681 } else {
3682 receiver = ComputeReceiverForNonGlobal(object);
3683 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003684 // No need to unhole the value here. This is taken care of by the
3685 // GetProperty function.
3686 Object* value = object->GetProperty(*name);
3687 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 }
3689
3690 if (throw_error) {
3691 // The property doesn't exist - throw exception.
3692 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003693 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 return MakePair(Top::Throw(*reference_error), NULL);
3695 } else {
3696 // The property doesn't exist - return undefined
3697 return MakePair(Heap::undefined_value(), Heap::undefined_value());
3698 }
3699}
3700
3701
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003702static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003703 return LoadContextSlotHelper(args, true);
3704}
3705
3706
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003707static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003708 return LoadContextSlotHelper(args, false);
3709}
3710
3711
3712static Object* Runtime_StoreContextSlot(Arguments args) {
3713 HandleScope scope;
3714 ASSERT(args.length() == 3);
3715
3716 Handle<Object> value(args[0]);
3717 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003718 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003719
3720 int index;
3721 PropertyAttributes attributes;
3722 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003723 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003724 context->Lookup(name, flags, &index, &attributes);
3725
3726 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003727 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728 // Ignore if read_only variable.
3729 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003730 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003731 }
3732 } else {
3733 ASSERT((attributes & READ_ONLY) == 0);
3734 Object* result =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003735 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003736 USE(result);
3737 ASSERT(!result->IsFailure());
3738 }
3739 return *value;
3740 }
3741
3742 // Slow case: The property is not in a FixedArray context.
3743 // It is either in an JSObject extension context or it was not found.
3744 Handle<JSObject> context_ext;
3745
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003746 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003747 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003748 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 } else {
3750 // The property was not found. It needs to be stored in the global context.
3751 ASSERT(attributes == ABSENT);
3752 attributes = NONE;
3753 context_ext = Handle<JSObject>(Top::context()->global());
3754 }
3755
3756 // Set the property, but ignore if read_only variable.
3757 if ((attributes & READ_ONLY) == 0) {
3758 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
3759 if (set.is_null()) {
3760 // Failure::Exception is converted to a null handle in the
3761 // handle-based methods such as SetProperty. We therefore need
3762 // to convert null handles back to exceptions.
3763 ASSERT(Top::has_pending_exception());
3764 return Failure::Exception();
3765 }
3766 }
3767 return *value;
3768}
3769
3770
3771static Object* Runtime_Throw(Arguments args) {
3772 HandleScope scope;
3773 ASSERT(args.length() == 1);
3774
3775 return Top::Throw(args[0]);
3776}
3777
3778
3779static Object* Runtime_ReThrow(Arguments args) {
3780 HandleScope scope;
3781 ASSERT(args.length() == 1);
3782
3783 return Top::ReThrow(args[0]);
3784}
3785
3786
3787static Object* Runtime_ThrowReferenceError(Arguments args) {
3788 HandleScope scope;
3789 ASSERT(args.length() == 1);
3790
3791 Handle<Object> name(args[0]);
3792 Handle<Object> reference_error =
3793 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
3794 return Top::Throw(*reference_error);
3795}
3796
3797
3798static Object* Runtime_StackOverflow(Arguments args) {
3799 NoHandleAllocation na;
3800 return Top::StackOverflow();
3801}
3802
3803
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003804static Object* Runtime_DebugBreak(Arguments args) {
3805 ASSERT(args.length() == 0);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003806 return Execution::DebugBreakHelper();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003807}
3808
3809
3810static Object* Runtime_StackGuard(Arguments args) {
3811 ASSERT(args.length() == 1);
3812
3813 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003814 if (StackGuard::IsStackOverflow()) {
3815 return Runtime_StackOverflow(args);
3816 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003817
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003818 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003819}
3820
3821
3822// NOTE: These PrintXXX functions are defined for all builds (not just
3823// DEBUG builds) because we may want to be able to trace function
3824// calls in all modes.
3825static void PrintString(String* str) {
3826 // not uncommon to have empty strings
3827 if (str->length() > 0) {
3828 SmartPointer<char> s =
3829 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3830 PrintF("%s", *s);
3831 }
3832}
3833
3834
3835static void PrintObject(Object* obj) {
3836 if (obj->IsSmi()) {
3837 PrintF("%d", Smi::cast(obj)->value());
3838 } else if (obj->IsString() || obj->IsSymbol()) {
3839 PrintString(String::cast(obj));
3840 } else if (obj->IsNumber()) {
3841 PrintF("%g", obj->Number());
3842 } else if (obj->IsFailure()) {
3843 PrintF("<failure>");
3844 } else if (obj->IsUndefined()) {
3845 PrintF("<undefined>");
3846 } else if (obj->IsNull()) {
3847 PrintF("<null>");
3848 } else if (obj->IsTrue()) {
3849 PrintF("<true>");
3850 } else if (obj->IsFalse()) {
3851 PrintF("<false>");
3852 } else {
3853 PrintF("%p", obj);
3854 }
3855}
3856
3857
3858static int StackSize() {
3859 int n = 0;
3860 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
3861 return n;
3862}
3863
3864
3865static void PrintTransition(Object* result) {
3866 // indentation
3867 { const int nmax = 80;
3868 int n = StackSize();
3869 if (n <= nmax)
3870 PrintF("%4d:%*s", n, n, "");
3871 else
3872 PrintF("%4d:%*s", n, nmax, "...");
3873 }
3874
3875 if (result == NULL) {
3876 // constructor calls
3877 JavaScriptFrameIterator it;
3878 JavaScriptFrame* frame = it.frame();
3879 if (frame->IsConstructor()) PrintF("new ");
3880 // function name
3881 Object* fun = frame->function();
3882 if (fun->IsJSFunction()) {
3883 PrintObject(JSFunction::cast(fun)->shared()->name());
3884 } else {
3885 PrintObject(fun);
3886 }
3887 // function arguments
3888 // (we are intentionally only printing the actually
3889 // supplied parameters, not all parameters required)
3890 PrintF("(this=");
3891 PrintObject(frame->receiver());
3892 const int length = frame->GetProvidedParametersCount();
3893 for (int i = 0; i < length; i++) {
3894 PrintF(", ");
3895 PrintObject(frame->GetParameter(i));
3896 }
3897 PrintF(") {\n");
3898
3899 } else {
3900 // function result
3901 PrintF("} -> ");
3902 PrintObject(result);
3903 PrintF("\n");
3904 }
3905}
3906
3907
3908static Object* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003909 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003910 NoHandleAllocation ha;
3911 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003912 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003913}
3914
3915
3916static Object* Runtime_TraceExit(Arguments args) {
3917 NoHandleAllocation ha;
3918 PrintTransition(args[0]);
3919 return args[0]; // return TOS
3920}
3921
3922
3923static Object* Runtime_DebugPrint(Arguments args) {
3924 NoHandleAllocation ha;
3925 ASSERT(args.length() == 1);
3926
3927#ifdef DEBUG
3928 if (args[0]->IsString()) {
3929 // If we have a string, assume it's a code "marker"
3930 // and print some interesting cpu debugging info.
3931 JavaScriptFrameIterator it;
3932 JavaScriptFrame* frame = it.frame();
3933 PrintF("fp = %p, sp = %p, pp = %p: ",
3934 frame->fp(), frame->sp(), frame->pp());
3935 } else {
3936 PrintF("DebugPrint: ");
3937 }
3938 args[0]->Print();
3939#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003940 // ShortPrint is available in release mode. Print is not.
3941 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003942#endif
3943 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00003944 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945
3946 return args[0]; // return TOS
3947}
3948
3949
3950static Object* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003951 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003952 NoHandleAllocation ha;
3953 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003954 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003955}
3956
3957
mads.s.ager31e71382008-08-13 09:32:07 +00003958static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003960 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961
3962 // According to ECMA-262, section 15.9.1, page 117, the precision of
3963 // the number in a Date object representing a particular instant in
3964 // time is milliseconds. Therefore, we floor the result of getting
3965 // the OS time.
3966 double millis = floor(OS::TimeCurrentMillis());
3967 return Heap::NumberFromDouble(millis);
3968}
3969
3970
3971static Object* Runtime_DateParseString(Arguments args) {
3972 HandleScope scope;
3973 ASSERT(args.length() == 1);
3974
3975 CONVERT_CHECKED(String, string_object, args[0]);
3976
3977 Handle<String> str(string_object);
3978 Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
3979 if (DateParser::Parse(*str, *output)) {
3980 return *Factory::NewJSArrayWithElements(output);
3981 } else {
3982 return *Factory::null_value();
3983 }
3984}
3985
3986
3987static Object* Runtime_DateLocalTimezone(Arguments args) {
3988 NoHandleAllocation ha;
3989 ASSERT(args.length() == 1);
3990
3991 CONVERT_DOUBLE_CHECKED(x, args[0]);
3992 char* zone = OS::LocalTimezone(x);
3993 return Heap::AllocateStringFromUtf8(CStrVector(zone));
3994}
3995
3996
3997static Object* Runtime_DateLocalTimeOffset(Arguments args) {
3998 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003999 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000
4001 return Heap::NumberFromDouble(OS::LocalTimeOffset());
4002}
4003
4004
4005static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
4006 NoHandleAllocation ha;
4007 ASSERT(args.length() == 1);
4008
4009 CONVERT_DOUBLE_CHECKED(x, args[0]);
4010 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
4011}
4012
4013
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014static Object* Runtime_NumberIsFinite(Arguments args) {
4015 NoHandleAllocation ha;
4016 ASSERT(args.length() == 1);
4017
4018 CONVERT_DOUBLE_CHECKED(value, args[0]);
4019 Object* result;
4020 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
4021 result = Heap::false_value();
4022 } else {
4023 result = Heap::true_value();
4024 }
4025 return result;
4026}
4027
4028
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004029static Object* Runtime_GlobalReceiver(Arguments args) {
4030 ASSERT(args.length() == 1);
4031 Object* global = args[0];
4032 if (!global->IsJSGlobalObject()) return Heap::null_value();
4033 return JSGlobalObject::cast(global)->global_receiver();
4034}
4035
4036
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004037static Object* Runtime_CompileString(Arguments args) {
4038 HandleScope scope;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004039 ASSERT(args.length() == 2);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004040 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org236ad962008-09-25 09:45:57 +00004041 CONVERT_ARG_CHECKED(Smi, line_offset, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004042
ager@chromium.org381abbb2009-02-25 13:23:22 +00004043 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004044 Handle<Context> context(Top::context()->global_context());
ager@chromium.org381abbb2009-02-25 13:23:22 +00004045 Handle<JSFunction> boilerplate =
4046 Compiler::CompileEval(source, context, line_offset->value(), true);
4047 if (boilerplate.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 Handle<JSFunction> fun =
4049 Factory::NewFunctionFromBoilerplate(boilerplate, context);
4050 return *fun;
4051}
4052
4053
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004054static Handle<JSFunction> GetBuiltinFunction(String* name) {
4055 LookupResult result;
4056 Top::global_context()->builtins()->LocalLookup(name, &result);
4057 return Handle<JSFunction>(JSFunction::cast(result.GetValue()));
4058}
4059
4060
4061static Object* CompileDirectEval(Handle<String> source) {
4062 // Compute the eval context.
4063 HandleScope scope;
4064 StackFrameLocator locator;
4065 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
4066 Handle<Context> context(Context::cast(frame->context()));
4067 bool is_global = context->IsGlobalContext();
4068
ager@chromium.org381abbb2009-02-25 13:23:22 +00004069 // Compile source string in the current context.
4070 Handle<JSFunction> boilerplate =
4071 Compiler::CompileEval(source, context, 0, is_global);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004072 if (boilerplate.is_null()) return Failure::Exception();
4073 Handle<JSFunction> fun =
4074 Factory::NewFunctionFromBoilerplate(boilerplate, context);
4075 return *fun;
4076}
4077
4078
4079static Object* Runtime_ResolvePossiblyDirectEval(Arguments args) {
4080 ASSERT(args.length() == 2);
4081
4082 HandleScope scope;
4083
4084 CONVERT_ARG_CHECKED(JSFunction, callee, 0);
4085
4086 Handle<Object> receiver;
4087
4088 // Find where the 'eval' symbol is bound. It is unaliased only if
4089 // it is bound in the global context.
4090 StackFrameLocator locator;
4091 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
4092 Handle<Context> context(Context::cast(frame->context()));
4093 int index;
4094 PropertyAttributes attributes;
4095 while (!context.is_null()) {
4096 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
4097 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00004098 // Stop search when eval is found or when the global context is
4099 // reached.
4100 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004101 if (context->is_function_context()) {
4102 context = Handle<Context>(Context::cast(context->closure()->context()));
4103 } else {
4104 context = Handle<Context>(context->previous());
4105 }
4106 }
4107
iposva@chromium.org245aa852009-02-10 00:49:54 +00004108 // If eval could not be resolved, it has been deleted and we need to
4109 // throw a reference error.
4110 if (attributes == ABSENT) {
4111 Handle<Object> name = Factory::eval_symbol();
4112 Handle<Object> reference_error =
4113 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
4114 return Top::Throw(*reference_error);
4115 }
4116
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004117 if (context->IsGlobalContext()) {
4118 // 'eval' is bound in the global context, but it may have been overwritten.
4119 // Compare it to the builtin 'GlobalEval' function to make sure.
4120 Handle<JSFunction> global_eval =
4121 GetBuiltinFunction(Heap::global_eval_symbol());
4122 if (global_eval.is_identical_to(callee)) {
4123 // A direct eval call.
4124 if (args[1]->IsString()) {
4125 CONVERT_ARG_CHECKED(String, source, 1);
4126 // A normal eval call on a string. Compile it and return the
4127 // compiled function bound in the local context.
4128 Object* compiled_source = CompileDirectEval(source);
4129 if (compiled_source->IsFailure()) return compiled_source;
4130 receiver = Handle<Object>(frame->receiver());
4131 callee = Handle<JSFunction>(JSFunction::cast(compiled_source));
4132 } else {
4133 // An eval call that is not called on a string. Global eval
4134 // deals better with this.
4135 receiver = Handle<Object>(Top::global_context()->global());
4136 }
4137 } else {
4138 // 'eval' is overwritten. Just call the function with the given arguments.
4139 receiver = Handle<Object>(Top::global_context()->global());
4140 }
4141 } else {
4142 // 'eval' is not bound in the global context. Just call the function
4143 // with the given arguments. This is not necessarily the global eval.
4144 if (receiver->IsContext()) {
4145 context = Handle<Context>::cast(receiver);
4146 receiver = Handle<Object>(context->get(index));
4147 }
4148 }
4149
4150 Handle<FixedArray> call = Factory::NewFixedArray(2);
4151 call->set(0, *callee);
4152 call->set(1, *receiver);
4153 return *call;
4154}
4155
4156
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004157static Object* Runtime_CompileScript(Arguments args) {
4158 HandleScope scope;
4159 ASSERT(args.length() == 4);
4160
4161 CONVERT_ARG_CHECKED(String, source, 0);
4162 CONVERT_ARG_CHECKED(String, script, 1);
4163 CONVERT_CHECKED(Smi, line_attrs, args[2]);
4164 int line = line_attrs->value();
4165 CONVERT_CHECKED(Smi, col_attrs, args[3]);
4166 int col = col_attrs->value();
4167 Handle<JSFunction> boilerplate =
4168 Compiler::Compile(source, script, line, col, NULL, NULL);
4169 if (boilerplate.is_null()) return Failure::Exception();
4170 Handle<JSFunction> fun =
4171 Factory::NewFunctionFromBoilerplate(boilerplate,
4172 Handle<Context>(Top::context()));
4173 return *fun;
4174}
4175
4176
4177static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
4178 // This utility adjusts the property attributes for newly created Function
4179 // object ("new Function(...)") by changing the map.
4180 // All it does is changing the prototype property to enumerable
4181 // as specified in ECMA262, 15.3.5.2.
4182 HandleScope scope;
4183 ASSERT(args.length() == 1);
4184 CONVERT_ARG_CHECKED(JSFunction, func, 0);
4185 ASSERT(func->map()->instance_type() ==
4186 Top::function_instance_map()->instance_type());
4187 ASSERT(func->map()->instance_size() ==
4188 Top::function_instance_map()->instance_size());
4189 func->set_map(*Top::function_instance_map());
4190 return *func;
4191}
4192
4193
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004194// Push an array unto an array of arrays if it is not already in the
4195// array. Returns true if the element was pushed on the stack and
4196// false otherwise.
4197static Object* Runtime_PushIfAbsent(Arguments args) {
4198 ASSERT(args.length() == 2);
4199 CONVERT_CHECKED(JSArray, array, args[0]);
4200 CONVERT_CHECKED(JSArray, element, args[1]);
4201 RUNTIME_ASSERT(array->HasFastElements());
4202 int length = Smi::cast(array->length())->value();
4203 FixedArray* elements = FixedArray::cast(array->elements());
4204 for (int i = 0; i < length; i++) {
4205 if (elements->get(i) == element) return Heap::false_value();
4206 }
4207 Object* obj = array->SetFastElement(length, element);
4208 if (obj->IsFailure()) return obj;
4209 return Heap::true_value();
4210}
4211
4212
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004213/**
4214 * A simple visitor visits every element of Array's.
4215 * The backend storage can be a fixed array for fast elements case,
4216 * or a dictionary for sparse array. Since Dictionary is a subtype
4217 * of FixedArray, the class can be used by both fast and slow cases.
4218 * The second parameter of the constructor, fast_elements, specifies
4219 * whether the storage is a FixedArray or Dictionary.
4220 *
4221 * An index limit is used to deal with the situation that a result array
4222 * length overflows 32-bit non-negative integer.
4223 */
4224class ArrayConcatVisitor {
4225 public:
4226 ArrayConcatVisitor(Handle<FixedArray> storage,
4227 uint32_t index_limit,
4228 bool fast_elements) :
4229 storage_(storage), index_limit_(index_limit),
4230 fast_elements_(fast_elements), index_offset_(0) { }
4231
4232 void visit(uint32_t i, Handle<Object> elm) {
4233 uint32_t index = i + index_offset_;
4234 if (index >= index_limit_) return;
4235
4236 if (fast_elements_) {
4237 ASSERT(index < static_cast<uint32_t>(storage_->length()));
4238 storage_->set(index, *elm);
4239
4240 } else {
4241 Handle<Dictionary> dict = Handle<Dictionary>::cast(storage_);
4242 Handle<Dictionary> result =
4243 Factory::DictionaryAtNumberPut(dict, index, elm);
4244 if (!result.is_identical_to(dict))
4245 storage_ = result;
4246 }
4247 }
4248
4249 void increase_index_offset(uint32_t delta) {
4250 index_offset_ += delta;
4251 }
4252
4253 private:
4254 Handle<FixedArray> storage_;
4255 uint32_t index_limit_;
4256 bool fast_elements_;
4257 uint32_t index_offset_;
4258};
4259
4260
4261/**
4262 * A helper function that visits elements of a JSObject. Only elements
4263 * whose index between 0 and range (exclusive) are visited.
4264 *
4265 * If the third parameter, visitor, is not NULL, the visitor is called
4266 * with parameters, 'visitor_index_offset + element index' and the element.
4267 *
4268 * It returns the number of visisted elements.
4269 */
4270static uint32_t IterateElements(Handle<JSObject> receiver,
4271 uint32_t range,
4272 ArrayConcatVisitor* visitor) {
4273 uint32_t num_of_elements = 0;
4274
4275 if (receiver->HasFastElements()) {
4276 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
4277 uint32_t len = elements->length();
4278 if (range < len) len = range;
4279
4280 for (uint32_t j = 0; j < len; j++) {
4281 Handle<Object> e(elements->get(j));
4282 if (!e->IsTheHole()) {
4283 num_of_elements++;
4284 if (visitor)
4285 visitor->visit(j, e);
4286 }
4287 }
4288
4289 } else {
4290 Handle<Dictionary> dict(receiver->element_dictionary());
4291 uint32_t capacity = dict->Capacity();
4292 for (uint32_t j = 0; j < capacity; j++) {
4293 Handle<Object> k(dict->KeyAt(j));
4294 if (dict->IsKey(*k)) {
4295 ASSERT(k->IsNumber());
4296 uint32_t index = static_cast<uint32_t>(k->Number());
4297 if (index < range) {
4298 num_of_elements++;
4299 if (visitor) {
4300 visitor->visit(index,
4301 Handle<Object>(dict->ValueAt(j)));
4302 }
4303 }
4304 }
4305 }
4306 }
4307
4308 return num_of_elements;
4309}
4310
4311
4312/**
4313 * A helper function that visits elements of an Array object, and elements
4314 * on its prototypes.
4315 *
4316 * Elements on prototypes are visited first, and only elements whose indices
4317 * less than Array length are visited.
4318 *
4319 * If a ArrayConcatVisitor object is given, the visitor is called with
4320 * parameters, element's index + visitor_index_offset and the element.
4321 */
4322static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
4323 ArrayConcatVisitor* visitor) {
4324 uint32_t range = static_cast<uint32_t>(array->length()->Number());
4325 Handle<Object> obj = array;
4326
4327 static const int kEstimatedPrototypes = 3;
4328 List< Handle<JSObject> > objects(kEstimatedPrototypes);
4329
4330 // Visit prototype first. If an element on the prototype is shadowed by
4331 // the inheritor using the same index, the ArrayConcatVisitor visits
4332 // the prototype element before the shadowing element.
4333 // The visitor can simply overwrite the old value by new value using
4334 // the same index. This follows Array::concat semantics.
4335 while (!obj->IsNull()) {
4336 objects.Add(Handle<JSObject>::cast(obj));
4337 obj = Handle<Object>(obj->GetPrototype());
4338 }
4339
4340 uint32_t nof_elements = 0;
4341 for (int i = objects.length() - 1; i >= 0; i--) {
4342 Handle<JSObject> obj = objects[i];
4343 nof_elements +=
4344 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
4345 }
4346
4347 return nof_elements;
4348}
4349
4350
4351/**
4352 * A helper function of Runtime_ArrayConcat.
4353 *
4354 * The first argument is an Array of arrays and objects. It is the
4355 * same as the arguments array of Array::concat JS function.
4356 *
4357 * If an argument is an Array object, the function visits array
4358 * elements. If an argument is not an Array object, the function
4359 * visits the object as if it is an one-element array.
4360 *
4361 * If the result array index overflows 32-bit integer, the rounded
4362 * non-negative number is used as new length. For example, if one
4363 * array length is 2^32 - 1, second array length is 1, the
4364 * concatenated array length is 0.
4365 */
4366static uint32_t IterateArguments(Handle<JSArray> arguments,
4367 ArrayConcatVisitor* visitor) {
4368 uint32_t visited_elements = 0;
4369 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
4370
4371 for (uint32_t i = 0; i < num_of_args; i++) {
4372 Handle<Object> obj(arguments->GetElement(i));
4373 if (obj->IsJSArray()) {
4374 Handle<JSArray> array = Handle<JSArray>::cast(obj);
4375 uint32_t len = static_cast<uint32_t>(array->length()->Number());
4376 uint32_t nof_elements =
4377 IterateArrayAndPrototypeElements(array, visitor);
4378 // Total elements of array and its prototype chain can be more than
4379 // the array length, but ArrayConcat can only concatenate at most
4380 // the array length number of elements.
4381 visited_elements += (nof_elements > len) ? len : nof_elements;
4382 if (visitor) visitor->increase_index_offset(len);
4383
4384 } else {
4385 if (visitor) {
4386 visitor->visit(0, obj);
4387 visitor->increase_index_offset(1);
4388 }
4389 visited_elements++;
4390 }
4391 }
4392 return visited_elements;
4393}
4394
4395
4396/**
4397 * Array::concat implementation.
4398 * See ECMAScript 262, 15.4.4.4.
4399 */
4400static Object* Runtime_ArrayConcat(Arguments args) {
4401 ASSERT(args.length() == 1);
4402 HandleScope handle_scope;
4403
4404 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
4405 Handle<JSArray> arguments(arg_arrays);
4406
4407 // Pass 1: estimate the number of elements of the result
4408 // (it could be more than real numbers if prototype has elements).
4409 uint32_t result_length = 0;
4410 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
4411
4412 { AssertNoAllocation nogc;
4413 for (uint32_t i = 0; i < num_of_args; i++) {
4414 Object* obj = arguments->GetElement(i);
4415 if (obj->IsJSArray()) {
4416 result_length +=
4417 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
4418 } else {
4419 result_length++;
4420 }
4421 }
4422 }
4423
4424 // Allocate an empty array, will set length and content later.
4425 Handle<JSArray> result = Factory::NewJSArray(0);
4426
4427 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
4428 // If estimated number of elements is more than half of length, a
4429 // fixed array (fast case) is more time and space-efficient than a
4430 // dictionary.
4431 bool fast_case = (estimate_nof_elements * 2) >= result_length;
4432
4433 Handle<FixedArray> storage;
4434 if (fast_case) {
4435 // The backing storage array must have non-existing elements to
4436 // preserve holes across concat operations.
4437 storage = Factory::NewFixedArrayWithHoles(result_length);
4438
4439 } else {
4440 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
4441 uint32_t at_least_space_for = estimate_nof_elements +
4442 (estimate_nof_elements >> 2);
4443 storage = Handle<FixedArray>::cast(
4444 Factory::NewDictionary(at_least_space_for));
4445 }
4446
4447 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
4448
4449 ArrayConcatVisitor visitor(storage, result_length, fast_case);
4450
4451 IterateArguments(arguments, &visitor);
4452
4453 result->set_length(*len);
4454 result->set_elements(*storage);
4455
4456 return *result;
4457}
4458
4459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460// This will not allocate (flatten the string), but it may run
4461// very slowly for very deeply nested ConsStrings. For debugging use only.
4462static Object* Runtime_GlobalPrint(Arguments args) {
4463 NoHandleAllocation ha;
4464 ASSERT(args.length() == 1);
4465
4466 CONVERT_CHECKED(String, string, args[0]);
4467 StringInputBuffer buffer(string);
4468 while (buffer.has_more()) {
4469 uint16_t character = buffer.GetNext();
4470 PrintF("%c", character);
4471 }
4472 return string;
4473}
4474
4475
4476static Object* Runtime_RemoveArrayHoles(Arguments args) {
4477 ASSERT(args.length() == 1);
4478 // Ignore the case if this is not a JSArray.
4479 if (!args[0]->IsJSArray()) return args[0];
4480 return JSArray::cast(args[0])->RemoveHoles();
4481}
4482
4483
4484// Move contents of argument 0 (an array) to argument 1 (an array)
4485static Object* Runtime_MoveArrayContents(Arguments args) {
4486 ASSERT(args.length() == 2);
4487 CONVERT_CHECKED(JSArray, from, args[0]);
4488 CONVERT_CHECKED(JSArray, to, args[1]);
4489 to->SetContent(FixedArray::cast(from->elements()));
4490 to->set_length(from->length());
4491 from->SetContent(Heap::empty_fixed_array());
4492 from->set_length(0);
4493 return to;
4494}
4495
4496
4497// How many elements does this array have?
4498static Object* Runtime_EstimateNumberOfElements(Arguments args) {
4499 ASSERT(args.length() == 1);
4500 CONVERT_CHECKED(JSArray, array, args[0]);
4501 HeapObject* elements = array->elements();
4502 if (elements->IsDictionary()) {
4503 return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
4504 } else {
4505 return array->length();
4506 }
4507}
4508
4509
4510// Returns an array that tells you where in the [0, length) interval an array
4511// might have elements. Can either return keys or intervals. Keys can have
4512// gaps in (undefined). Intervals can also span over some undefined keys.
4513static Object* Runtime_GetArrayKeys(Arguments args) {
4514 ASSERT(args.length() == 2);
4515 HandleScope scope;
4516 CONVERT_CHECKED(JSArray, raw_array, args[0]);
4517 Handle<JSArray> array(raw_array);
4518 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004519 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004520 // Create an array and get all the keys into it, then remove all the
4521 // keys that are not integers in the range 0 to length-1.
4522 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
4523 int keys_length = keys->length();
4524 for (int i = 0; i < keys_length; i++) {
4525 Object* key = keys->get(i);
4526 uint32_t index;
4527 if (!Array::IndexFromObject(key, &index) || index >= length) {
4528 // Zap invalid keys.
4529 keys->set_undefined(i);
4530 }
4531 }
4532 return *Factory::NewJSArrayWithElements(keys);
4533 } else {
4534 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
4535 // -1 means start of array.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004536 single_interval->set(0,
4537 Smi::FromInt(-1),
4538 SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004539 Handle<Object> length_object =
4540 Factory::NewNumber(static_cast<double>(length));
4541 single_interval->set(1, *length_object);
4542 return *Factory::NewJSArrayWithElements(single_interval);
4543 }
4544}
4545
4546
4547// DefineAccessor takes an optional final argument which is the
4548// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
4549// to the way accessors are implemented, it is set for both the getter
4550// and setter on the first call to DefineAccessor and ignored on
4551// subsequent calls.
4552static Object* Runtime_DefineAccessor(Arguments args) {
4553 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
4554 // Compute attributes.
4555 PropertyAttributes attributes = NONE;
4556 if (args.length() == 5) {
4557 CONVERT_CHECKED(Smi, attrs, args[4]);
4558 int value = attrs->value();
4559 // Only attribute bits should be set.
4560 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4561 attributes = static_cast<PropertyAttributes>(value);
4562 }
4563
4564 CONVERT_CHECKED(JSObject, obj, args[0]);
4565 CONVERT_CHECKED(String, name, args[1]);
4566 CONVERT_CHECKED(Smi, flag, args[2]);
4567 CONVERT_CHECKED(JSFunction, fun, args[3]);
4568 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
4569}
4570
4571
4572static Object* Runtime_LookupAccessor(Arguments args) {
4573 ASSERT(args.length() == 3);
4574 CONVERT_CHECKED(JSObject, obj, args[0]);
4575 CONVERT_CHECKED(String, name, args[1]);
4576 CONVERT_CHECKED(Smi, flag, args[2]);
4577 return obj->LookupAccessor(name, flag->value() == 0);
4578}
4579
4580
4581// Helper functions for wrapping and unwrapping stack frame ids.
4582static Smi* WrapFrameId(StackFrame::Id id) {
4583 ASSERT(IsAligned(OffsetFrom(id), 4));
4584 return Smi::FromInt(id >> 2);
4585}
4586
4587
4588static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
4589 return static_cast<StackFrame::Id>(wrapped->value() << 2);
4590}
4591
4592
4593// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00004594// args[0]: debug event listener function to set or null or undefined for
4595// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004596// args[1]: object supplied during callback
iposva@chromium.org245aa852009-02-10 00:49:54 +00004597static Object* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00004599 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
4600 args[0]->IsUndefined() ||
4601 args[0]->IsNull());
4602 Handle<Object> callback = args.at<Object>(0);
4603 Handle<Object> data = args.at<Object>(1);
4604 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605
4606 return Heap::undefined_value();
4607}
4608
4609
4610static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004611 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004612 StackGuard::DebugBreak();
4613 return Heap::undefined_value();
4614}
4615
4616
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004617// Find the length of the prototype chain that is to to handled as one. If a
4618// prototype object is hidden it is to be viewed as part of the the object it
4619// is prototype for.
4620static int LocalPrototypeChainLength(JSObject* obj) {
4621 int count = 1;
4622 Object* proto = obj->GetPrototype();
4623 while (proto->IsJSObject() &&
4624 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4625 count++;
4626 proto = JSObject::cast(proto)->GetPrototype();
4627 }
4628 return count;
4629}
4630
4631
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004632static Object* DebugLookupResultValue(Object* receiver, LookupResult* result,
ager@chromium.org32912102009-01-16 10:38:43 +00004633 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004634 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004635 switch (result->type()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004636 case NORMAL: {
4637 Dictionary* dict =
4638 JSObject::cast(result->holder())->property_dictionary();
4639 value = dict->ValueAt(result->GetDictionaryEntry());
4640 if (value->IsTheHole()) {
4641 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004642 }
4643 return value;
4644 }
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004645 case FIELD:
4646 value =
4647 JSObject::cast(
4648 result->holder())->FastPropertyAt(result->GetFieldIndex());
4649 if (value->IsTheHole()) {
4650 return Heap::undefined_value();
4651 }
4652 return value;
4653 case CONSTANT_FUNCTION:
4654 return result->GetConstantFunction();
4655 case CALLBACKS: {
4656 Object* structure = result->GetCallbackObject();
4657 if (structure->IsProxy()) {
4658 AccessorDescriptor* callback =
4659 reinterpret_cast<AccessorDescriptor*>(
4660 Proxy::cast(structure)->proxy());
4661 value = (callback->getter)(receiver, callback->data);
ager@chromium.org381abbb2009-02-25 13:23:22 +00004662 if (value->IsException()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004663 value = Top::pending_exception();
4664 Top::clear_pending_exception();
4665 if (caught_exception != NULL) {
4666 *caught_exception = true;
4667 }
4668 }
4669 return value;
4670 } else {
4671 return Heap::undefined_value();
4672 }
4673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004674 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004675 case MAP_TRANSITION:
4676 case CONSTANT_TRANSITION:
4677 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004678 return Heap::undefined_value();
4679 default:
4680 UNREACHABLE();
4681 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004682 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683 return Heap::undefined_value();
4684}
4685
4686
ager@chromium.org32912102009-01-16 10:38:43 +00004687// Get debugger related details for an object property.
4688// args[0]: object holding property
4689// args[1]: name of the property
4690//
4691// The array returned contains the following information:
4692// 0: Property value
4693// 1: Property details
4694// 2: Property value is exception
4695// 3: Getter function if defined
4696// 4: Setter function if defined
4697// Items 2-4 are only filled if the property has either a getter or a setter
4698// defined through __defineGetter__ and/or __defineSetter__.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004699static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004700 HandleScope scope;
4701
4702 ASSERT(args.length() == 2);
4703
4704 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4705 CONVERT_ARG_CHECKED(String, name, 1);
4706
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004707 // Skip the global proxy as it has no properties and always delegates to the
4708 // real global object.
4709 if (obj->IsJSGlobalProxy()) {
4710 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4711 }
4712
4713
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714 // Check if the name is trivially convertible to an index and get the element
4715 // if so.
4716 uint32_t index;
4717 if (name->AsArrayIndex(&index)) {
4718 Handle<FixedArray> details = Factory::NewFixedArray(2);
4719 details->set(0, Runtime::GetElementOrCharAt(obj, index));
4720 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
4721 return *Factory::NewJSArrayWithElements(details);
4722 }
4723
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004724 // Find the number of objects making up this.
4725 int length = LocalPrototypeChainLength(*obj);
4726
4727 // Try local lookup on each of the objects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004728 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004729 Handle<JSObject> jsproto = obj;
4730 for (int i = 0; i < length; i++) {
4731 jsproto->LocalLookup(*name, &result);
4732 if (result.IsProperty()) {
4733 break;
4734 }
4735 if (i < length - 1) {
4736 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4737 }
4738 }
4739
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004740 if (result.IsProperty()) {
ager@chromium.org32912102009-01-16 10:38:43 +00004741 bool caught_exception = false;
ager@chromium.org381abbb2009-02-25 13:23:22 +00004742 Object* value = DebugLookupResultValue(*obj, &result,
4743 &caught_exception);
4744 if (value->IsFailure()) return value;
4745 Handle<Object> value_handle(value);
ager@chromium.org32912102009-01-16 10:38:43 +00004746 // If the callback object is a fixed array then it contains JavaScript
4747 // getter and/or setter.
4748 bool hasJavaScriptAccessors = result.type() == CALLBACKS &&
4749 result.GetCallbackObject()->IsFixedArray();
4750 Handle<FixedArray> details =
4751 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +00004752 details->set(0, *value_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004753 details->set(1, result.GetPropertyDetails().AsSmi());
ager@chromium.org32912102009-01-16 10:38:43 +00004754 if (hasJavaScriptAccessors) {
4755 details->set(2,
4756 caught_exception ? Heap::true_value() : Heap::false_value());
4757 details->set(3, FixedArray::cast(result.GetCallbackObject())->get(0));
4758 details->set(4, FixedArray::cast(result.GetCallbackObject())->get(1));
4759 }
4760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761 return *Factory::NewJSArrayWithElements(details);
4762 }
4763 return Heap::undefined_value();
4764}
4765
4766
4767static Object* Runtime_DebugGetProperty(Arguments args) {
4768 HandleScope scope;
4769
4770 ASSERT(args.length() == 2);
4771
4772 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4773 CONVERT_ARG_CHECKED(String, name, 1);
4774
4775 LookupResult result;
4776 obj->Lookup(*name, &result);
4777 if (result.IsProperty()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004778 return DebugLookupResultValue(*obj, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779 }
4780 return Heap::undefined_value();
4781}
4782
4783
4784// Return the names of the local named properties.
4785// args[0]: object
4786static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
4787 HandleScope scope;
4788 ASSERT(args.length() == 1);
4789 if (!args[0]->IsJSObject()) {
4790 return Heap::undefined_value();
4791 }
4792 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4793
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004794 // Skip the global proxy as it has no properties and always delegates to the
4795 // real global object.
4796 if (obj->IsJSGlobalProxy()) {
4797 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4798 }
4799
4800 // Find the number of objects making up this.
4801 int length = LocalPrototypeChainLength(*obj);
4802
4803 // Find the number of local properties for each of the objects.
4804 int* local_property_count = NewArray<int>(length);
4805 int total_property_count = 0;
4806 Handle<JSObject> jsproto = obj;
4807 for (int i = 0; i < length; i++) {
4808 int n;
4809 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4810 local_property_count[i] = n;
4811 total_property_count += n;
4812 if (i < length - 1) {
4813 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4814 }
4815 }
4816
4817 // Allocate an array with storage for all the property names.
4818 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4819
4820 // Get the property names.
4821 jsproto = obj;
4822 for (int i = 0; i < length; i++) {
4823 jsproto->GetLocalPropertyNames(*names,
4824 i == 0 ? 0 : local_property_count[i - 1]);
4825 if (i < length - 1) {
4826 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4827 }
4828 }
4829
4830 DeleteArray(local_property_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 return *Factory::NewJSArrayWithElements(names);
4832}
4833
4834
4835// Return the names of the local indexed properties.
4836// args[0]: object
4837static Object* Runtime_DebugLocalElementNames(Arguments args) {
4838 HandleScope scope;
4839 ASSERT(args.length() == 1);
4840 if (!args[0]->IsJSObject()) {
4841 return Heap::undefined_value();
4842 }
4843 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4844
4845 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4846 Handle<FixedArray> names = Factory::NewFixedArray(n);
4847 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4848 return *Factory::NewJSArrayWithElements(names);
4849}
4850
4851
4852// Return the property type calculated from the property details.
4853// args[0]: smi with property details.
4854static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
4855 ASSERT(args.length() == 1);
4856 CONVERT_CHECKED(Smi, details, args[0]);
4857 PropertyType type = PropertyDetails(details).type();
4858 return Smi::FromInt(static_cast<int>(type));
4859}
4860
4861
4862// Return the property attribute calculated from the property details.
4863// args[0]: smi with property details.
4864static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
4865 ASSERT(args.length() == 1);
4866 CONVERT_CHECKED(Smi, details, args[0]);
4867 PropertyAttributes attributes = PropertyDetails(details).attributes();
4868 return Smi::FromInt(static_cast<int>(attributes));
4869}
4870
4871
4872// Return the property insertion index calculated from the property details.
4873// args[0]: smi with property details.
4874static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
4875 ASSERT(args.length() == 1);
4876 CONVERT_CHECKED(Smi, details, args[0]);
4877 int index = PropertyDetails(details).index();
4878 return Smi::FromInt(index);
4879}
4880
4881
4882// Return information on whether an object has a named or indexed interceptor.
4883// args[0]: object
4884static Object* Runtime_DebugInterceptorInfo(Arguments args) {
4885 HandleScope scope;
4886 ASSERT(args.length() == 1);
4887 if (!args[0]->IsJSObject()) {
4888 return Smi::FromInt(0);
4889 }
4890 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4891
4892 int result = 0;
4893 if (obj->HasNamedInterceptor()) result |= 2;
4894 if (obj->HasIndexedInterceptor()) result |= 1;
4895
4896 return Smi::FromInt(result);
4897}
4898
4899
4900// Return property names from named interceptor.
4901// args[0]: object
4902static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
4903 HandleScope scope;
4904 ASSERT(args.length() == 1);
4905 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004906
ager@chromium.org32912102009-01-16 10:38:43 +00004907 if (obj->HasNamedInterceptor()) {
4908 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4909 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4910 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004911 return Heap::undefined_value();
4912}
4913
4914
4915// Return element names from indexed interceptor.
4916// args[0]: object
4917static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
4918 HandleScope scope;
4919 ASSERT(args.length() == 1);
4920 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004921
ager@chromium.org32912102009-01-16 10:38:43 +00004922 if (obj->HasIndexedInterceptor()) {
4923 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4924 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4925 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004926 return Heap::undefined_value();
4927}
4928
4929
4930// Return property value from named interceptor.
4931// args[0]: object
4932// args[1]: property name
4933static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
4934 HandleScope scope;
4935 ASSERT(args.length() == 2);
4936 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4937 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4938 CONVERT_ARG_CHECKED(String, name, 1);
4939
4940 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004941 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004942}
4943
4944
4945// Return element value from indexed interceptor.
4946// args[0]: object
4947// args[1]: index
4948static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
4949 HandleScope scope;
4950 ASSERT(args.length() == 2);
4951 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4952 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4953 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
4954
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004955 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004956}
4957
4958
4959static Object* Runtime_CheckExecutionState(Arguments args) {
4960 ASSERT(args.length() >= 1);
4961 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004962 // Check that the break id is valid.
4963 if (Top::break_id() == 0 || break_id != Top::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004964 return Top::Throw(Heap::illegal_execution_state_symbol());
4965 }
4966
4967 return Heap::true_value();
4968}
4969
4970
4971static Object* Runtime_GetFrameCount(Arguments args) {
4972 HandleScope scope;
4973 ASSERT(args.length() == 1);
4974
4975 // Check arguments.
4976 Object* result = Runtime_CheckExecutionState(args);
4977 if (result->IsFailure()) return result;
4978
4979 // Count all frames which are relevant to debugging stack trace.
4980 int n = 0;
4981 StackFrame::Id id = Top::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00004982 if (id == StackFrame::NO_ID) {
4983 // If there is no JavaScript stack frame count is 0.
4984 return Smi::FromInt(0);
4985 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004986 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
4987 return Smi::FromInt(n);
4988}
4989
4990
4991static const int kFrameDetailsFrameIdIndex = 0;
4992static const int kFrameDetailsReceiverIndex = 1;
4993static const int kFrameDetailsFunctionIndex = 2;
4994static const int kFrameDetailsArgumentCountIndex = 3;
4995static const int kFrameDetailsLocalCountIndex = 4;
4996static const int kFrameDetailsSourcePositionIndex = 5;
4997static const int kFrameDetailsConstructCallIndex = 6;
4998static const int kFrameDetailsDebuggerFrameIndex = 7;
4999static const int kFrameDetailsFirstDynamicIndex = 8;
5000
5001// Return an array with frame details
5002// args[0]: number: break id
5003// args[1]: number: frame index
5004//
5005// The array returned contains the following information:
5006// 0: Frame id
5007// 1: Receiver
5008// 2: Function
5009// 3: Argument count
5010// 4: Local count
5011// 5: Source position
5012// 6: Constructor call
5013// 7: Debugger frame
5014// Arguments name, value
5015// Locals name, value
5016static Object* Runtime_GetFrameDetails(Arguments args) {
5017 HandleScope scope;
5018 ASSERT(args.length() == 2);
5019
5020 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005021 Object* check = Runtime_CheckExecutionState(args);
5022 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005023 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
5024
5025 // Find the relevant frame with the requested index.
5026 StackFrame::Id id = Top::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00005027 if (id == StackFrame::NO_ID) {
5028 // If there are no JavaScript stack frames return undefined.
5029 return Heap::undefined_value();
5030 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005031 int count = 0;
5032 JavaScriptFrameIterator it(id);
5033 for (; !it.done(); it.Advance()) {
5034 if (count == index) break;
5035 count++;
5036 }
5037 if (it.done()) return Heap::undefined_value();
5038
5039 // Traverse the saved contexts chain to find the active context for the
5040 // selected frame.
5041 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005042 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005043 save = save->prev();
5044 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005045 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005046
5047 // Get the frame id.
5048 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
5049
5050 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005051 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005052
5053 // Check for constructor frame.
5054 bool constructor = it.frame()->IsConstructor();
5055
5056 // Get code and read scope info from it for local variable information.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005057 Handle<Code> code(it.frame()->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005058 ScopeInfo<> info(*code);
5059
5060 // Get the context.
5061 Handle<Context> context(Context::cast(it.frame()->context()));
5062
5063 // Get the locals names and values into a temporary array.
5064 //
5065 // TODO(1240907): Hide compiler-introduced stack variables
5066 // (e.g. .result)? For users of the debugger, they will probably be
5067 // confusing.
5068 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
5069 for (int i = 0; i < info.NumberOfLocals(); i++) {
5070 // Name of the local.
5071 locals->set(i * 2, *info.LocalName(i));
5072
5073 // Fetch the value of the local - either from the stack or from a
5074 // heap-allocated context.
5075 if (i < info.number_of_stack_slots()) {
5076 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
5077 } else {
5078 Handle<String> name = info.LocalName(i);
5079 // Traverse the context chain to the function context as all local
5080 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005081 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005082 context = Handle<Context>(context->previous());
5083 }
5084 ASSERT(context->is_function_context());
5085 locals->set(i * 2 + 1,
5086 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
5087 NULL)));
5088 }
5089 }
5090
5091 // Now advance to the arguments adapter frame (if any). If contains all
5092 // the provided parameters and
5093
5094 // Now advance to the arguments adapter frame (if any). It contains all
5095 // the provided parameters whereas the function frame always have the number
5096 // of arguments matching the functions parameters. The rest of the
5097 // information (except for what is collected above) is the same.
5098 it.AdvanceToArgumentsFrame();
5099
5100 // Find the number of arguments to fill. At least fill the number of
5101 // parameters for the function and fill more if more parameters are provided.
5102 int argument_count = info.number_of_parameters();
5103 if (argument_count < it.frame()->GetProvidedParametersCount()) {
5104 argument_count = it.frame()->GetProvidedParametersCount();
5105 }
5106
5107 // Calculate the size of the result.
5108 int details_size = kFrameDetailsFirstDynamicIndex +
5109 2 * (argument_count + info.NumberOfLocals());
5110 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
5111
5112 // Add the frame id.
5113 details->set(kFrameDetailsFrameIdIndex, *frame_id);
5114
5115 // Add the function (same as in function frame).
5116 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
5117
5118 // Add the arguments count.
5119 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
5120
5121 // Add the locals count
5122 details->set(kFrameDetailsLocalCountIndex,
5123 Smi::FromInt(info.NumberOfLocals()));
5124
5125 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00005126 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005127 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
5128 } else {
5129 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
5130 }
5131
5132 // Add the constructor information.
5133 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
5134
5135 // Add information on whether this frame is invoked in the debugger context.
5136 details->set(kFrameDetailsDebuggerFrameIndex,
5137 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
5138
5139 // Fill the dynamic part.
5140 int details_index = kFrameDetailsFirstDynamicIndex;
5141
5142 // Add arguments name and value.
5143 for (int i = 0; i < argument_count; i++) {
5144 // Name of the argument.
5145 if (i < info.number_of_parameters()) {
5146 details->set(details_index++, *info.parameter_name(i));
5147 } else {
5148 details->set(details_index++, Heap::undefined_value());
5149 }
5150
5151 // Parameter value.
5152 if (i < it.frame()->GetProvidedParametersCount()) {
5153 details->set(details_index++, it.frame()->GetParameter(i));
5154 } else {
5155 details->set(details_index++, Heap::undefined_value());
5156 }
5157 }
5158
5159 // Add locals name and value from the temporary copy from the function frame.
5160 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
5161 details->set(details_index++, locals->get(i));
5162 }
5163
5164 // Add the receiver (same as in function frame).
5165 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
5166 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
5167 Handle<Object> receiver(it.frame()->receiver());
5168 if (!receiver->IsJSObject()) {
5169 // If the receiver is NOT a JSObject we have hit an optimization
5170 // where a value object is not converted into a wrapped JS objects.
5171 // To hide this optimization from the debugger, we wrap the receiver
5172 // by creating correct wrapper object based on the calling frame's
5173 // global context.
5174 it.Advance();
5175 Handle<Context> calling_frames_global_context(
5176 Context::cast(Context::cast(it.frame()->context())->global_context()));
5177 receiver = Factory::ToObject(receiver, calling_frames_global_context);
5178 }
5179 details->set(kFrameDetailsReceiverIndex, *receiver);
5180
5181 ASSERT_EQ(details_size, details_index);
5182 return *Factory::NewJSArrayWithElements(details);
5183}
5184
5185
5186static Object* Runtime_GetCFrames(Arguments args) {
5187 HandleScope scope;
5188 ASSERT(args.length() == 1);
5189 Object* result = Runtime_CheckExecutionState(args);
5190 if (result->IsFailure()) return result;
5191
5192 static const int kMaxCFramesSize = 200;
5193 OS::StackFrame frames[kMaxCFramesSize];
5194 int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
5195 if (frames_count == OS::kStackWalkError) {
5196 return Heap::undefined_value();
5197 }
5198
5199 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
5200 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
5201 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
5202 for (int i = 0; i < frames_count; i++) {
5203 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
5204 frame_value->SetProperty(
5205 *address_str,
5206 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
5207 NONE);
5208
5209 // Get the stack walk text for this frame.
5210 Handle<String> frame_text;
5211 if (strlen(frames[i].text) > 0) {
5212 Vector<const char> str(frames[i].text, strlen(frames[i].text));
5213 frame_text = Factory::NewStringFromAscii(str);
5214 }
5215
5216 if (!frame_text.is_null()) {
5217 frame_value->SetProperty(*text_str, *frame_text, NONE);
5218 }
5219
5220 frames_array->set(i, *frame_value);
5221 }
5222 return *Factory::NewJSArrayWithElements(frames_array);
5223}
5224
5225
5226static Object* Runtime_GetBreakLocations(Arguments args) {
5227 HandleScope scope;
5228 ASSERT(args.length() == 1);
5229
5230 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
5231 Handle<SharedFunctionInfo> shared(raw_fun->shared());
5232 // Find the number of break points
5233 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
5234 if (break_locations->IsUndefined()) return Heap::undefined_value();
5235 // Return array as JS array
5236 return *Factory::NewJSArrayWithElements(
5237 Handle<FixedArray>::cast(break_locations));
5238}
5239
5240
5241// Set a break point in a function
5242// args[0]: function
5243// args[1]: number: break source position (within the function source)
5244// args[2]: number: break point object
5245static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
5246 HandleScope scope;
5247 ASSERT(args.length() == 3);
5248 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
5249 Handle<SharedFunctionInfo> shared(raw_fun->shared());
5250 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
5251 RUNTIME_ASSERT(source_position >= 0);
5252 Handle<Object> break_point_object_arg = args.at<Object>(2);
5253
5254 // Set break point.
5255 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
5256
5257 return Heap::undefined_value();
5258}
5259
5260
5261static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
5262 int position) {
5263 // Iterate the heap looking for SharedFunctionInfo generated from the
5264 // script. The inner most SharedFunctionInfo containing the source position
5265 // for the requested break point is found.
5266 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
5267 // which is found is not compiled it is compiled and the heap is iterated
5268 // again as the compilation might create inner functions from the newly
5269 // compiled function and the actual requested break point might be in one of
5270 // these functions.
5271 bool done = false;
5272 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00005273 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005274 Handle<SharedFunctionInfo> target;
5275 // The current candidate for the last function in script:
5276 Handle<SharedFunctionInfo> last;
5277 while (!done) {
5278 HeapIterator iterator;
5279 while (iterator.has_next()) {
5280 HeapObject* obj = iterator.next();
5281 ASSERT(obj != NULL);
5282 if (obj->IsSharedFunctionInfo()) {
5283 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
5284 if (shared->script() == *script) {
5285 // If the SharedFunctionInfo found has the requested script data and
5286 // contains the source position it is a candidate.
5287 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00005288 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005289 start_position = shared->start_position();
5290 }
5291 if (start_position <= position &&
5292 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00005293 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005294 // candidate this is the new candidate.
5295 if (target.is_null()) {
5296 target_start_position = start_position;
5297 target = shared;
5298 } else {
5299 if (target_start_position < start_position &&
5300 shared->end_position() < target->end_position()) {
5301 target_start_position = start_position;
5302 target = shared;
5303 }
5304 }
5305 }
5306
5307 // Keep track of the last function in the script.
5308 if (last.is_null() ||
5309 shared->end_position() > last->start_position()) {
5310 last = shared;
5311 }
5312 }
5313 }
5314 }
5315
5316 // Make sure some candidate is selected.
5317 if (target.is_null()) {
5318 if (!last.is_null()) {
5319 // Position after the last function - use last.
5320 target = last;
5321 } else {
5322 // Unable to find function - possibly script without any function.
5323 return Heap::undefined_value();
5324 }
5325 }
5326
5327 // If the candidate found is compiled we are done. NOTE: when lazy
5328 // compilation of inner functions is introduced some additional checking
5329 // needs to be done here to compile inner functions.
5330 done = target->is_compiled();
5331 if (!done) {
5332 // If the candidate is not compiled compile it to reveal any inner
5333 // functions which might contain the requested source position.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005334 CompileLazyShared(target, KEEP_EXCEPTION, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005335 }
5336 }
5337
5338 return *target;
5339}
5340
5341
5342// Change the state of a break point in a script. NOTE: Regarding performance
5343// see the NOTE for GetScriptFromScriptData.
5344// args[0]: script to set break point in
5345// args[1]: number: break source position (within the script source)
5346// args[2]: number: break point object
5347static Object* Runtime_SetScriptBreakPoint(Arguments args) {
5348 HandleScope scope;
5349 ASSERT(args.length() == 3);
5350 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
5351 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
5352 RUNTIME_ASSERT(source_position >= 0);
5353 Handle<Object> break_point_object_arg = args.at<Object>(2);
5354
5355 // Get the script from the script wrapper.
5356 RUNTIME_ASSERT(wrapper->value()->IsScript());
5357 Handle<Script> script(Script::cast(wrapper->value()));
5358
5359 Object* result = FindSharedFunctionInfoInScript(script, source_position);
5360 if (!result->IsUndefined()) {
5361 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
5362 // Find position within function. The script position might be before the
5363 // source position of the first function.
5364 int position;
5365 if (shared->start_position() > source_position) {
5366 position = 0;
5367 } else {
5368 position = source_position - shared->start_position();
5369 }
5370 Debug::SetBreakPoint(shared, position, break_point_object_arg);
5371 }
5372 return Heap::undefined_value();
5373}
5374
5375
5376// Clear a break point
5377// args[0]: number: break point object
5378static Object* Runtime_ClearBreakPoint(Arguments args) {
5379 HandleScope scope;
5380 ASSERT(args.length() == 1);
5381 Handle<Object> break_point_object_arg = args.at<Object>(0);
5382
5383 // Clear break point.
5384 Debug::ClearBreakPoint(break_point_object_arg);
5385
5386 return Heap::undefined_value();
5387}
5388
5389
5390// Change the state of break on exceptions
5391// args[0]: boolean indicating uncaught exceptions
5392// args[1]: boolean indicating on/off
5393static Object* Runtime_ChangeBreakOnException(Arguments args) {
5394 HandleScope scope;
5395 ASSERT(args.length() == 2);
5396 ASSERT(args[0]->IsNumber());
5397 ASSERT(args[1]->IsBoolean());
5398
5399 // Update break point state
5400 ExceptionBreakType type =
5401 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
5402 bool enable = args[1]->ToBoolean()->IsTrue();
5403 Debug::ChangeBreakOnException(type, enable);
5404 return Heap::undefined_value();
5405}
5406
5407
5408// Prepare for stepping
5409// args[0]: break id for checking execution state
5410// args[1]: step action from the enumeration StepAction
5411// args[2]: number of times to perform the step
5412static Object* Runtime_PrepareStep(Arguments args) {
5413 HandleScope scope;
5414 ASSERT(args.length() == 3);
5415 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005416 Object* check = Runtime_CheckExecutionState(args);
5417 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005418 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
5419 return Top::Throw(Heap::illegal_argument_symbol());
5420 }
5421
5422 // Get the step action and check validity.
5423 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
5424 if (step_action != StepIn &&
5425 step_action != StepNext &&
5426 step_action != StepOut &&
5427 step_action != StepInMin &&
5428 step_action != StepMin) {
5429 return Top::Throw(Heap::illegal_argument_symbol());
5430 }
5431
5432 // Get the number of steps.
5433 int step_count = NumberToInt32(args[2]);
5434 if (step_count < 1) {
5435 return Top::Throw(Heap::illegal_argument_symbol());
5436 }
5437
5438 // Prepare step.
5439 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
5440 return Heap::undefined_value();
5441}
5442
5443
5444// Clear all stepping set by PrepareStep.
5445static Object* Runtime_ClearStepping(Arguments args) {
5446 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00005447 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005448 Debug::ClearStepping();
5449 return Heap::undefined_value();
5450}
5451
5452
5453// Creates a copy of the with context chain. The copy of the context chain is
5454// is linked to the function context supplied.
5455static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
5456 Handle<Context> function_context) {
5457 // At the bottom of the chain. Return the function context to link to.
5458 if (context_chain->is_function_context()) {
5459 return function_context;
5460 }
5461
5462 // Recursively copy the with contexts.
5463 Handle<Context> previous(context_chain->previous());
5464 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
5465 return Factory::NewWithContext(
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005466 CopyWithContextChain(function_context, previous),
5467 extension,
5468 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005469}
5470
5471
5472// Helper function to find or create the arguments object for
5473// Runtime_DebugEvaluate.
5474static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
5475 Handle<JSFunction> function,
5476 Handle<Code> code,
5477 const ScopeInfo<>* sinfo,
5478 Handle<Context> function_context) {
5479 // Try to find the value of 'arguments' to pass as parameter. If it is not
5480 // found (that is the debugged function does not reference 'arguments' and
5481 // does not support eval) then create an 'arguments' object.
5482 int index;
5483 if (sinfo->number_of_stack_slots() > 0) {
5484 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
5485 if (index != -1) {
5486 return Handle<Object>(frame->GetExpression(index));
5487 }
5488 }
5489
5490 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
5491 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
5492 NULL);
5493 if (index != -1) {
5494 return Handle<Object>(function_context->get(index));
5495 }
5496 }
5497
5498 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005499 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
5500 Handle<FixedArray> array = Factory::NewFixedArray(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005501 WriteBarrierMode mode = array->GetWriteBarrierMode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005503 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005505 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005506 return arguments;
5507}
5508
5509
5510// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00005511// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005512// extension part has all the parameters and locals of the function on the
5513// stack frame. A function which calls eval with the code to evaluate is then
5514// compiled in this context and called in this context. As this context
5515// replaces the context of the function on the stack frame a new (empty)
5516// function is created as well to be used as the closure for the context.
5517// This function and the context acts as replacements for the function on the
5518// stack frame presenting the same view of the values of parameters and
5519// local variables as if the piece of JavaScript was evaluated at the point
5520// where the function on the stack frame is currently stopped.
5521static Object* Runtime_DebugEvaluate(Arguments args) {
5522 HandleScope scope;
5523
5524 // Check the execution state and decode arguments frame and source to be
5525 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005526 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005527 Object* check_result = Runtime_CheckExecutionState(args);
5528 if (check_result->IsFailure()) return check_result;
5529 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
5530 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005531 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
5532
5533 // Handle the processing of break.
5534 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005535
5536 // Get the frame where the debugging is performed.
5537 StackFrame::Id id = UnwrapFrameId(wrapped_id);
5538 JavaScriptFrameIterator it(id);
5539 JavaScriptFrame* frame = it.frame();
5540 Handle<JSFunction> function(JSFunction::cast(frame->function()));
5541 Handle<Code> code(function->code());
5542 ScopeInfo<> sinfo(*code);
5543
5544 // Traverse the saved contexts chain to find the active context for the
5545 // selected frame.
5546 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005547 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005548 save = save->prev();
5549 }
5550 ASSERT(save != NULL);
5551 SaveContext savex;
5552 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005553
5554 // Create the (empty) function replacing the function on the stack frame for
5555 // the purpose of evaluating in the context created below. It is important
5556 // that this function does not describe any parameters and local variables
5557 // in the context. If it does then this will cause problems with the lookup
5558 // in Context::Lookup, where context slots for parameters and local variables
5559 // are looked at before the extension object.
5560 Handle<JSFunction> go_between =
5561 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
5562 go_between->set_context(function->context());
5563#ifdef DEBUG
5564 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
5565 ASSERT(go_between_sinfo.number_of_parameters() == 0);
5566 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
5567#endif
5568
5569 // Allocate and initialize a context extension object with all the
5570 // arguments, stack locals heap locals and extension properties of the
5571 // debugged function.
5572 Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
5573 // First fill all parameters to the context extension.
5574 for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
5575 SetProperty(context_ext,
5576 sinfo.parameter_name(i),
5577 Handle<Object>(frame->GetParameter(i)), NONE);
5578 }
5579 // Second fill all stack locals to the context extension.
5580 for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
5581 SetProperty(context_ext,
5582 sinfo.stack_slot_name(i),
5583 Handle<Object>(frame->GetExpression(i)), NONE);
5584 }
5585 // Third fill all context locals to the context extension.
5586 Handle<Context> frame_context(Context::cast(frame->context()));
5587 Handle<Context> function_context(frame_context->fcontext());
5588 for (int i = Context::MIN_CONTEXT_SLOTS;
5589 i < sinfo.number_of_context_slots();
5590 ++i) {
5591 int context_index =
5592 ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
5593 SetProperty(context_ext,
5594 sinfo.context_slot_name(i),
5595 Handle<Object>(function_context->get(context_index)), NONE);
5596 }
5597 // Finally copy any properties from the function context extension. This will
5598 // be variables introduced by eval.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005599 if (function_context->has_extension() &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005600 !function_context->IsGlobalContext()) {
5601 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
5602 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
5603 for (int i = 0; i < keys->length(); i++) {
5604 // Names of variables introduced by eval are strings.
5605 ASSERT(keys->get(i)->IsString());
5606 Handle<String> key(String::cast(keys->get(i)));
5607 SetProperty(context_ext, key, GetProperty(ext, key), NONE);
5608 }
5609 }
5610
5611 // Allocate a new context for the debug evaluation and set the extension
5612 // object build.
5613 Handle<Context> context =
5614 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
5615 context->set_extension(*context_ext);
5616 // Copy any with contexts present and chain them in front of this context.
5617 context = CopyWithContextChain(frame_context, context);
5618
5619 // Wrap the evaluation statement in a new function compiled in the newly
5620 // created context. The function has one parameter which has to be called
5621 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00005622 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005623 // function(arguments,__source__) {return eval(__source__);}
5624 static const char* source_str =
5625 "function(arguments,__source__){return eval(__source__);}";
5626 static const int source_str_length = strlen(source_str);
5627 Handle<String> function_source =
5628 Factory::NewStringFromAscii(Vector<const char>(source_str,
5629 source_str_length));
5630 Handle<JSFunction> boilerplate =
ager@chromium.org381abbb2009-02-25 13:23:22 +00005631 Compiler::CompileEval(function_source,
5632 context,
5633 0,
5634 context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005635 if (boilerplate.is_null()) return Failure::Exception();
5636 Handle<JSFunction> compiled_function =
5637 Factory::NewFunctionFromBoilerplate(boilerplate, context);
5638
5639 // Invoke the result of the compilation to get the evaluation function.
5640 bool has_pending_exception;
5641 Handle<Object> receiver(frame->receiver());
5642 Handle<Object> evaluation_function =
5643 Execution::Call(compiled_function, receiver, 0, NULL,
5644 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005645 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005646
5647 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
5648 function_context);
5649
5650 // Invoke the evaluation function and return the result.
5651 const int argc = 2;
5652 Object** argv[argc] = { arguments.location(),
5653 Handle<Object>::cast(source).location() };
5654 Handle<Object> result =
5655 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
5656 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005657 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005658 return *result;
5659}
5660
5661
5662static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
5663 HandleScope scope;
5664
5665 // Check the execution state and decode arguments frame and source to be
5666 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005667 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005668 Object* check_result = Runtime_CheckExecutionState(args);
5669 if (check_result->IsFailure()) return check_result;
5670 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005671 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
5672
5673 // Handle the processing of break.
5674 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005675
5676 // Enter the top context from before the debugger was invoked.
5677 SaveContext save;
5678 SaveContext* top = &save;
5679 while (top != NULL && *top->context() == *Debug::debug_context()) {
5680 top = top->prev();
5681 }
5682 if (top != NULL) {
5683 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005684 }
5685
5686 // Get the global context now set to the top context from before the
5687 // debugger was invoked.
5688 Handle<Context> context = Top::global_context();
5689
5690 // Compile the source to be evaluated.
ager@chromium.org381abbb2009-02-25 13:23:22 +00005691 Handle<JSFunction> boilerplate =
5692 Handle<JSFunction>(Compiler::CompileEval(source, context, 0, true));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005693 if (boilerplate.is_null()) return Failure::Exception();
5694 Handle<JSFunction> compiled_function =
5695 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
5696 context));
5697
5698 // Invoke the result of the compilation to get the evaluation function.
5699 bool has_pending_exception;
5700 Handle<Object> receiver = Top::global();
5701 Handle<Object> result =
5702 Execution::Call(compiled_function, receiver, 0, NULL,
5703 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005704 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005705 return *result;
5706}
5707
5708
5709// Helper function used by Runtime_DebugGetLoadedScripts below.
5710static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
5711 NoHandleAllocation ha;
5712 AssertNoAllocation no_alloc;
5713
5714 // Get hold of the current empty script.
5715 Context* context = Top::context()->global_context();
5716 Script* empty = context->empty_script();
5717
5718 // Scan heap for Script objects.
5719 int count = 0;
5720 HeapIterator iterator;
5721 while (iterator.has_next()) {
5722 HeapObject* obj = iterator.next();
5723 ASSERT(obj != NULL);
5724 if (obj->IsScript() && obj != empty) {
5725 if (instances != NULL && count < instances_size) {
5726 instances->set(count, obj);
5727 }
5728 count++;
5729 }
5730 }
5731
5732 return count;
5733}
5734
5735
5736static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
5737 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00005738 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005739
5740 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
ager@chromium.org32912102009-01-16 10:38:43 +00005741 // rid of all the cached script wrappers and the second gets rid of the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005742 // scripts which is no longer referenced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005743 Heap::CollectAllGarbage();
5744 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005745
5746 // Get the number of scripts.
5747 int count;
5748 count = DebugGetLoadedScripts(NULL, 0);
5749
5750 // Allocate an array to hold the result.
5751 Handle<FixedArray> instances = Factory::NewFixedArray(count);
5752
5753 // Fill the script objects.
5754 count = DebugGetLoadedScripts(*instances, count);
5755
5756 // Convert the script objects to proper JS objects.
5757 for (int i = 0; i < count; i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005758 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
5759 // Get the script wrapper in a local handle before calling GetScriptWrapper,
5760 // because using
5761 // instances->set(i, *GetScriptWrapper(script))
5762 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
5763 // already have deferenced the instances handle.
5764 Handle<JSValue> wrapper = GetScriptWrapper(script);
5765 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005766 }
5767
5768 // Return result as a JS array.
5769 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
5770 Handle<JSArray>::cast(result)->SetContent(*instances);
5771 return *result;
5772}
5773
5774
5775// Helper function used by Runtime_DebugReferencedBy below.
5776static int DebugReferencedBy(JSObject* target,
5777 Object* instance_filter, int max_references,
5778 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005779 JSFunction* arguments_function) {
5780 NoHandleAllocation ha;
5781 AssertNoAllocation no_alloc;
5782
5783 // Iterate the heap.
5784 int count = 0;
5785 JSObject* last = NULL;
5786 HeapIterator iterator;
5787 while (iterator.has_next() &&
5788 (max_references == 0 || count < max_references)) {
5789 // Only look at all JSObjects.
5790 HeapObject* heap_obj = iterator.next();
5791 if (heap_obj->IsJSObject()) {
5792 // Skip context extension objects and argument arrays as these are
5793 // checked in the context of functions using them.
5794 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00005795 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005796 obj->map()->constructor() == arguments_function) {
5797 continue;
5798 }
5799
5800 // Check if the JS object has a reference to the object looked for.
5801 if (obj->ReferencesObject(target)) {
5802 // Check instance filter if supplied. This is normally used to avoid
5803 // references from mirror objects (see Runtime_IsInPrototypeChain).
5804 if (!instance_filter->IsUndefined()) {
5805 Object* V = obj;
5806 while (true) {
5807 Object* prototype = V->GetPrototype();
5808 if (prototype->IsNull()) {
5809 break;
5810 }
5811 if (instance_filter == prototype) {
5812 obj = NULL; // Don't add this object.
5813 break;
5814 }
5815 V = prototype;
5816 }
5817 }
5818
5819 if (obj != NULL) {
5820 // Valid reference found add to instance array if supplied an update
5821 // count.
5822 if (instances != NULL && count < instances_size) {
5823 instances->set(count, obj);
5824 }
5825 last = obj;
5826 count++;
5827 }
5828 }
5829 }
5830 }
5831
5832 // Check for circular reference only. This can happen when the object is only
5833 // referenced from mirrors and has a circular reference in which case the
5834 // object is not really alive and would have been garbage collected if not
5835 // referenced from the mirror.
5836 if (count == 1 && last == target) {
5837 count = 0;
5838 }
5839
5840 // Return the number of referencing objects found.
5841 return count;
5842}
5843
5844
5845// Scan the heap for objects with direct references to an object
5846// args[0]: the object to find references to
5847// args[1]: constructor function for instances to exclude (Mirror)
5848// args[2]: the the maximum number of objects to return
5849static Object* Runtime_DebugReferencedBy(Arguments args) {
5850 ASSERT(args.length() == 3);
5851
5852 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005853 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854
5855 // Check parameters.
5856 CONVERT_CHECKED(JSObject, target, args[0]);
5857 Object* instance_filter = args[1];
5858 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
5859 instance_filter->IsJSObject());
5860 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
5861 RUNTIME_ASSERT(max_references >= 0);
5862
5863 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005864 JSObject* arguments_boilerplate =
5865 Top::context()->global_context()->arguments_boilerplate();
5866 JSFunction* arguments_function =
5867 JSFunction::cast(arguments_boilerplate->map()->constructor());
5868
5869 // Get the number of referencing objects.
5870 int count;
5871 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00005872 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005873
5874 // Allocate an array to hold the result.
5875 Object* object = Heap::AllocateFixedArray(count);
5876 if (object->IsFailure()) return object;
5877 FixedArray* instances = FixedArray::cast(object);
5878
5879 // Fill the referencing objects.
5880 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00005881 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005882
5883 // Return result as JS array.
5884 Object* result =
5885 Heap::AllocateJSObject(
5886 Top::context()->global_context()->array_function());
5887 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5888 return result;
5889}
5890
5891
5892// Helper function used by Runtime_DebugConstructedBy below.
5893static int DebugConstructedBy(JSFunction* constructor, int max_references,
5894 FixedArray* instances, int instances_size) {
5895 AssertNoAllocation no_alloc;
5896
5897 // Iterate the heap.
5898 int count = 0;
5899 HeapIterator iterator;
5900 while (iterator.has_next() &&
5901 (max_references == 0 || count < max_references)) {
5902 // Only look at all JSObjects.
5903 HeapObject* heap_obj = iterator.next();
5904 if (heap_obj->IsJSObject()) {
5905 JSObject* obj = JSObject::cast(heap_obj);
5906 if (obj->map()->constructor() == constructor) {
5907 // Valid reference found add to instance array if supplied an update
5908 // count.
5909 if (instances != NULL && count < instances_size) {
5910 instances->set(count, obj);
5911 }
5912 count++;
5913 }
5914 }
5915 }
5916
5917 // Return the number of referencing objects found.
5918 return count;
5919}
5920
5921
5922// Scan the heap for objects constructed by a specific function.
5923// args[0]: the constructor to find instances of
5924// args[1]: the the maximum number of objects to return
5925static Object* Runtime_DebugConstructedBy(Arguments args) {
5926 ASSERT(args.length() == 2);
5927
5928 // First perform a full GC in order to avoid dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005929 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005930
5931 // Check parameters.
5932 CONVERT_CHECKED(JSFunction, constructor, args[0]);
5933 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
5934 RUNTIME_ASSERT(max_references >= 0);
5935
5936 // Get the number of referencing objects.
5937 int count;
5938 count = DebugConstructedBy(constructor, max_references, NULL, 0);
5939
5940 // Allocate an array to hold the result.
5941 Object* object = Heap::AllocateFixedArray(count);
5942 if (object->IsFailure()) return object;
5943 FixedArray* instances = FixedArray::cast(object);
5944
5945 // Fill the referencing objects.
5946 count = DebugConstructedBy(constructor, max_references, instances, count);
5947
5948 // Return result as JS array.
5949 Object* result =
5950 Heap::AllocateJSObject(
5951 Top::context()->global_context()->array_function());
5952 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5953 return result;
5954}
5955
5956
ager@chromium.orgddb913d2009-01-27 10:01:48 +00005957// Find the effective prototype object as returned by __proto__.
5958// args[0]: the object to find the prototype for.
5959static Object* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960 ASSERT(args.length() == 1);
5961
5962 CONVERT_CHECKED(JSObject, obj, args[0]);
5963
ager@chromium.orgddb913d2009-01-27 10:01:48 +00005964 // Use the __proto__ accessor.
5965 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966}
5967
5968
5969static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005970 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 CPU::DebugBreak();
5972 return Heap::undefined_value();
5973}
5974
5975
5976// Finds the script object from the script data. NOTE: This operation uses
5977// heap traversal to find the function generated for the source position
5978// for the requested break point. For lazily compiled functions several heap
5979// traversals might be required rendering this operation as a rather slow
5980// operation. However for setting break points which is normally done through
5981// some kind of user interaction the performance is not crucial.
5982static Handle<Object> Runtime_GetScriptFromScriptName(
5983 Handle<String> script_name) {
5984 // Scan the heap for Script objects to find the script with the requested
5985 // script data.
5986 Handle<Script> script;
5987 HeapIterator iterator;
5988 while (script.is_null() && iterator.has_next()) {
5989 HeapObject* obj = iterator.next();
5990 // If a script is found check if it has the script data requested.
5991 if (obj->IsScript()) {
5992 if (Script::cast(obj)->name()->IsString()) {
5993 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
5994 script = Handle<Script>(Script::cast(obj));
5995 }
5996 }
5997 }
5998 }
5999
6000 // If no script with the requested script data is found return undefined.
6001 if (script.is_null()) return Factory::undefined_value();
6002
6003 // Return the script found.
6004 return GetScriptWrapper(script);
6005}
6006
6007
6008// Get the script object from script data. NOTE: Regarding performance
6009// see the NOTE for GetScriptFromScriptData.
6010// args[0]: script data for the script to find the source for
6011static Object* Runtime_GetScript(Arguments args) {
6012 HandleScope scope;
6013
6014 ASSERT(args.length() == 1);
6015
6016 CONVERT_CHECKED(String, script_name, args[0]);
6017
6018 // Find the requested script.
6019 Handle<Object> result =
6020 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
6021 return *result;
6022}
6023
6024
6025static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
6026#ifdef DEBUG
6027 HandleScope scope;
6028 ASSERT(args.length() == 1);
6029 // Get the function and make sure it is compiled.
6030 CONVERT_ARG_CHECKED(JSFunction, func, 0);
6031 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
6032 return Failure::Exception();
6033 }
6034 func->code()->PrintLn();
6035#endif // DEBUG
6036 return Heap::undefined_value();
6037}
6038
6039
6040static Object* Runtime_Abort(Arguments args) {
6041 ASSERT(args.length() == 2);
6042 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
6043 Smi::cast(args[1])->value());
6044 Top::PrintStack();
6045 OS::Abort();
6046 UNREACHABLE();
6047 return NULL;
6048}
6049
6050
kasper.lund44510672008-07-25 07:37:58 +00006051#ifdef DEBUG
6052// ListNatives is ONLY used by the fuzz-natives.js in debug mode
6053// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00006055 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006056 HandleScope scope;
6057 Handle<JSArray> result = Factory::NewJSArray(0);
6058 int index = 0;
6059#define ADD_ENTRY(Name, argc) \
6060 { \
6061 HandleScope inner; \
6062 Handle<String> name = \
6063 Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
6064 Handle<JSArray> pair = Factory::NewJSArray(0); \
6065 SetElement(pair, 0, name); \
6066 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
6067 SetElement(result, index++, pair); \
6068 }
6069 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
6070#undef ADD_ENTRY
6071 return *result;
6072}
kasper.lund44510672008-07-25 07:37:58 +00006073#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006074
6075
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006076static Object* Runtime_Log(Arguments args) {
6077 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +00006078 CONVERT_CHECKED(String, format, args[0]);
6079 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006080 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006081 Logger::LogRuntime(chars, elms);
6082 return Heap::undefined_value();
6083}
6084
6085
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006086static Object* Runtime_IS_VAR(Arguments args) {
6087 UNREACHABLE(); // implemented as macro in the parser
6088 return NULL;
6089}
6090
6091
6092// ----------------------------------------------------------------------------
6093// Implementation of Runtime
6094
6095#define F(name, nargs) \
6096 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
6097 static_cast<int>(Runtime::k##name) },
6098
6099static Runtime::Function Runtime_functions[] = {
6100 RUNTIME_FUNCTION_LIST(F)
6101 { NULL, NULL, NULL, 0, -1 }
6102};
6103
6104#undef F
6105
6106
6107Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
6108 ASSERT(0 <= fid && fid < kNofFunctions);
6109 return &Runtime_functions[fid];
6110}
6111
6112
6113Runtime::Function* Runtime::FunctionForName(const char* name) {
6114 for (Function* f = Runtime_functions; f->name != NULL; f++) {
6115 if (strcmp(f->name, name) == 0) {
6116 return f;
6117 }
6118 }
6119 return NULL;
6120}
6121
6122
6123void Runtime::PerformGC(Object* result) {
6124 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006125 if (failure->IsRetryAfterGC()) {
6126 // Try to do a garbage collection; ignore it if it fails. The C
6127 // entry stub will throw an out-of-memory exception in that case.
6128 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
6129 } else {
6130 // Handle last resort GC and make sure to allow future allocations
6131 // to grow the heap without causing GCs (if possible).
6132 Counters::gc_last_resort_from_js.Increment();
6133 Heap::CollectAllGarbage();
6134 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006135}
6136
6137
6138} } // namespace v8::internal