blob: 3ea93049c01d63cf4357430ed3ed39db7f4f1ded [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000046#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000047#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000048#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000049#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000050#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000055#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000057#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000058#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000059#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
kasperl@chromium.org71affb52009-05-26 05:44:31 +000061namespace v8 {
62namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64
ager@chromium.org3e875802009-06-29 08:26:34 +000065#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000066 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067
68// Cast the given object to a value of the specified type and store
69// it in a variable with the given name. If the object is not of the
70// expected type call IllegalOperation and return.
71#define CONVERT_CHECKED(Type, name, obj) \
72 RUNTIME_ASSERT(obj->Is##Type()); \
73 Type* name = Type::cast(obj);
74
75#define CONVERT_ARG_CHECKED(Type, name, index) \
76 RUNTIME_ASSERT(args[index]->Is##Type()); \
77 Handle<Type> name = args.at<Type>(index);
78
kasper.lundbd3ec4e2008-07-09 11:06:54 +000079// Cast the given object to a boolean and store it in a variable with
80// the given name. If the object is not a boolean call IllegalOperation
81// and return.
82#define CONVERT_BOOLEAN_CHECKED(name, obj) \
83 RUNTIME_ASSERT(obj->IsBoolean()); \
84 bool name = (obj)->IsTrue();
85
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000086// Cast the given argument to a Smi and store its value in an int variable
87// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000088// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000089#define CONVERT_SMI_ARG_CHECKED(name, index) \
90 RUNTIME_ASSERT(args[index]->IsSmi()); \
91 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000092
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000093// Cast the given argument to a double and store it in a variable with
94// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000096#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
97 RUNTIME_ASSERT(args[index]->IsNumber()); \
98 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099
100// Call the specified converter on the object *comand store the result in
101// a variable of the specified type with the given name. If the
102// object is not a Number call IllegalOperation and return.
103#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
104 RUNTIME_ASSERT(obj->IsNumber()); \
105 type name = NumberTo##Type(obj);
106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000108MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
109 JSObject* boilerplate) {
110 StackLimitCheck check(isolate);
111 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000115 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000116 if (!maybe_result->ToObject(&result)) return maybe_result;
117 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 JSObject* copy = JSObject::cast(result);
119
120 // Deep copy local properties.
121 if (copy->HasFastProperties()) {
122 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000123 for (int i = 0; i < properties->length(); i++) {
124 Object* value = properties->get(i);
125 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000127 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000128 if (!maybe_result->ToObject(&result)) return maybe_result;
129 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000130 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 }
132 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000133 int nof = copy->map()->inobject_properties();
134 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000135 Object* value = copy->InObjectPropertyAt(i);
136 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 }
143 }
144 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 FixedArray* names = FixedArray::cast(result);
150 copy->GetLocalPropertyNames(names, 0);
151 for (int i = 0; i < names->length(); i++) {
152 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000155 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000156 // Only deep copy fields from the object literal expression.
157 // In particular, don't try to copy the length attribute of
158 // an array.
159 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000160 Object* value =
161 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000164 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000165 if (!maybe_result->ToObject(&result)) return maybe_result;
166 }
167 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000168 // Creating object copy for literals. No strict mode needed.
169 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 }
173 }
174 }
175
176 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000178 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000179 switch (copy->GetElementsKind()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000180 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000181 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000182 if (elements->map() == heap->fixed_cow_array_map()) {
183 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000184#ifdef DEBUG
185 for (int i = 0; i < elements->length(); i++) {
186 ASSERT(!elements->get(i)->IsJSObject());
187 }
188#endif
189 } else {
190 for (int i = 0; i < elements->length(); i++) {
191 Object* value = elements->get(i);
192 if (value->IsJSObject()) {
193 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
195 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000198 elements->set(i, result);
199 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 }
201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000204 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000205 NumberDictionary* element_dictionary = copy->element_dictionary();
206 int capacity = element_dictionary->Capacity();
207 for (int i = 0; i < capacity; i++) {
208 Object* k = element_dictionary->KeyAt(i);
209 if (element_dictionary->IsKey(k)) {
210 Object* value = element_dictionary->ValueAt(i);
211 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000212 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
214 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000215 if (!maybe_result->ToObject(&result)) return maybe_result;
216 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 element_dictionary->ValueAtPut(i, result);
218 }
219 }
220 }
221 break;
222 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000223 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000224 UNIMPLEMENTED();
225 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000226 case EXTERNAL_PIXEL_ELEMENTS:
227 case EXTERNAL_BYTE_ELEMENTS:
228 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
229 case EXTERNAL_SHORT_ELEMENTS:
230 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
231 case EXTERNAL_INT_ELEMENTS:
232 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
233 case EXTERNAL_FLOAT_ELEMENTS:
234 case EXTERNAL_DOUBLE_ELEMENTS:
235 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000236 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
239 return copy;
240}
241
242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000243RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000244 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000246}
247
248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000249RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000251 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252}
253
254
ager@chromium.org236ad962008-09-25 09:45:57 +0000255static Handle<Map> ComputeObjectLiteralMap(
256 Handle<Context> context,
257 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000258 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000259 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000260 int properties_length = constant_properties->length();
261 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000262 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000263 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 for (int p = 0; p != properties_length; p += 2) {
266 Object* key = constant_properties->get(p);
267 uint32_t element_index = 0;
268 if (key->IsSymbol()) {
269 number_of_symbol_keys++;
270 } else if (key->ToArrayIndex(&element_index)) {
271 // An index key does not require space in the property backing store.
272 number_of_properties--;
273 } else {
274 // Bail out as a non-symbol non-index key makes caching impossible.
275 // ASSERT to make sure that the if condition after the loop is false.
276 ASSERT(number_of_symbol_keys != number_of_properties);
277 break;
278 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000279 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000280 // If we only have symbols and array indices among keys then we can
281 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000282 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 if ((number_of_symbol_keys == number_of_properties) &&
284 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 Handle<FixedArray> keys =
287 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000288 if (number_of_symbol_keys > 0) {
289 int index = 0;
290 for (int p = 0; p < properties_length; p += 2) {
291 Object* key = constant_properties->get(p);
292 if (key->IsSymbol()) {
293 keys->set(index++, key);
294 }
295 }
296 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000297 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000298 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000299 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
301 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000302 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000304 Handle<Map>(context->object_function()->initial_map()),
305 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000306}
307
308
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000309static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000310 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000311 Handle<FixedArray> literals,
312 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000314
315static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000317 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000318 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000319 bool should_have_fast_elements,
320 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000321 // Get the global context from the literals array. This is the
322 // context in which the function was created and we use the object
323 // function from this context to create the object literal. We do
324 // not use the object function from the current global context
325 // because this might be the object function from another context
326 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000327 Handle<Context> context =
328 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // In case we have function literals, we want the object to be in
331 // slow properties mode for now. We don't go in the map cache because
332 // maps with constant functions can't be shared if the functions are
333 // not the same (which is the common case).
334 bool is_result_from_cache = false;
335 Handle<Map> map = has_function_literal
336 ? Handle<Map>(context->object_function()->initial_map())
337 : ComputeObjectLiteralMap(context,
338 constant_properties,
339 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000341 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000342
343 // Normalize the elements of the boilerplate to save space if needed.
344 if (!should_have_fast_elements) NormalizeElements(boilerplate);
345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 // Add the constant properties to the boilerplate.
347 int length = constant_properties->length();
348 bool should_transform =
349 !is_result_from_cache && boilerplate->HasFastProperties();
350 if (should_transform || has_function_literal) {
351 // Normalize the properties of object to avoid n^2 behavior
352 // when extending the object multiple properties. Indicate the number of
353 // properties to be added.
354 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
355 }
356
357 for (int index = 0; index < length; index +=2) {
358 Handle<Object> key(constant_properties->get(index+0), isolate);
359 Handle<Object> value(constant_properties->get(index+1), isolate);
360 if (value->IsFixedArray()) {
361 // The value contains the constant_properties of a
362 // simple object or array literal.
363 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
364 value = CreateLiteralBoilerplate(isolate, literals, array);
365 if (value.is_null()) return value;
366 }
367 Handle<Object> result;
368 uint32_t element_index = 0;
369 if (key->IsSymbol()) {
370 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
371 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000372 result = SetOwnElement(boilerplate,
373 element_index,
374 value,
375 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000376 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 Handle<String> name(String::cast(*key));
378 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000379 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
380 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000382 } else if (key->ToArrayIndex(&element_index)) {
383 // Array index (uint32).
384 result = SetOwnElement(boilerplate,
385 element_index,
386 value,
387 kNonStrictMode);
388 } else {
389 // Non-uint32 number.
390 ASSERT(key->IsNumber());
391 double num = key->Number();
392 char arr[100];
393 Vector<char> buffer(arr, ARRAY_SIZE(arr));
394 const char* str = DoubleToCString(num, buffer);
395 Handle<String> name =
396 isolate->factory()->NewStringFromAscii(CStrVector(str));
397 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
398 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000400 // If setting the property on the boilerplate throws an
401 // exception, the exception is converted to an empty handle in
402 // the handle based operations. In that case, we need to
403 // convert back to an exception.
404 if (result.is_null()) return result;
405 }
406
407 // Transform to fast properties if necessary. For object literals with
408 // containing function literals we defer this operation until after all
409 // computed properties have been assigned so that we can generate
410 // constant function properties.
411 if (should_transform && !has_function_literal) {
412 TransformToFastProperties(boilerplate,
413 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 }
415
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000416 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000417}
418
419
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000420static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000421 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000422 Handle<FixedArray> literals,
423 Handle<FixedArray> elements) {
424 // Create the JSArray.
425 Handle<JSFunction> constructor(
426 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000427 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 const bool is_cow =
430 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433
434 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 if (is_cow) {
436#ifdef DEBUG
437 // Copy-on-write arrays must be shallow (and simple).
438 for (int i = 0; i < content->length(); i++) {
439 ASSERT(!content->get(i)->IsFixedArray());
440 }
441#endif
442 } else {
443 for (int i = 0; i < content->length(); i++) {
444 if (content->get(i)->IsFixedArray()) {
445 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000446 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000447 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
448 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000450 if (result.is_null()) return result;
451 content->set(i, *result);
452 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 }
454 }
455
456 // Set the elements.
457 Handle<JSArray>::cast(object)->SetContent(*content);
458 return object;
459}
460
461
462static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000464 Handle<FixedArray> literals,
465 Handle<FixedArray> array) {
466 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000469 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 return CreateObjectLiteralBoilerplate(isolate,
471 literals,
472 elements,
473 true,
474 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000475 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000476 return CreateObjectLiteralBoilerplate(isolate,
477 literals,
478 elements,
479 false,
480 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 default:
484 UNREACHABLE();
485 return Handle<Object>::null();
486 }
487}
488
489
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000490RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000491 // Takes a FixedArray of elements containing the literal elements of
492 // the array literal and produces JSArray with those elements.
493 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000494 // which contains the context from which to get the Array function
495 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000496 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000497 ASSERT(args.length() == 3);
498 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000499 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000500 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 Handle<Object> object =
503 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000504 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000506 // Update the functions literal and return the boilerplate.
507 literals->set(literals_index, *object);
508 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509}
510
511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000512RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000514 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000516 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000517 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000518 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
520 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521
522 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 Handle<Object> boilerplate(literals->get(literals_index), isolate);
524 if (*boilerplate == isolate->heap()->undefined_value()) {
525 boilerplate = CreateObjectLiteralBoilerplate(isolate,
526 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 should_have_fast_elements,
529 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000530 if (boilerplate.is_null()) return Failure::Exception();
531 // Update the functions literal and return the boilerplate.
532 literals->set(literals_index, *boilerplate);
533 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000535}
536
537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000538RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000540 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000541 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000542 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000543 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000544 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
546 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547
548 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 Handle<Object> boilerplate(literals->get(literals_index), isolate);
550 if (*boilerplate == isolate->heap()->undefined_value()) {
551 boilerplate = CreateObjectLiteralBoilerplate(isolate,
552 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000553 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 should_have_fast_elements,
555 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556 if (boilerplate.is_null()) return Failure::Exception();
557 // Update the functions literal and return the boilerplate.
558 literals->set(literals_index, *boilerplate);
559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561}
562
563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000564RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566 ASSERT(args.length() == 3);
567 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000568 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
570
571 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 Handle<Object> boilerplate(literals->get(literals_index), isolate);
573 if (*boilerplate == isolate->heap()->undefined_value()) {
574 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 if (boilerplate.is_null()) return Failure::Exception();
576 // Update the functions literal and return the boilerplate.
577 literals->set(literals_index, *boilerplate);
578 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580}
581
582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000583RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 ASSERT(args.length() == 3);
586 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000587 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
589
590 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 Handle<Object> boilerplate(literals->get(literals_index), isolate);
592 if (*boilerplate == isolate->heap()->undefined_value()) {
593 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000594 if (boilerplate.is_null()) return Failure::Exception();
595 // Update the functions literal and return the boilerplate.
596 literals->set(literals_index, *boilerplate);
597 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000598 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000600 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000601 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000603}
604
605
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000606RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
607 ASSERT(args.length() == 2);
608 Object* handler = args[0];
609 Object* prototype = args[1];
610 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000611 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000612 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
613}
614
615
lrn@chromium.org34e60782011-09-15 07:25:40 +0000616RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
617 ASSERT(args.length() == 4);
618 Object* handler = args[0];
619 Object* call_trap = args[1];
620 Object* construct_trap = args[2];
621 Object* prototype = args[3];
622 Object* used_prototype =
623 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
624 return isolate->heap()->AllocateJSFunctionProxy(
625 handler, call_trap, construct_trap, used_prototype);
626}
627
628
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000629RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
630 ASSERT(args.length() == 1);
631 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000632 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000633}
634
635
lrn@chromium.org34e60782011-09-15 07:25:40 +0000636RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
637 ASSERT(args.length() == 1);
638 Object* obj = args[0];
639 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
640}
641
642
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000643RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
644 ASSERT(args.length() == 1);
645 CONVERT_CHECKED(JSProxy, proxy, args[0]);
646 return proxy->handler();
647}
648
649
lrn@chromium.org34e60782011-09-15 07:25:40 +0000650RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
651 ASSERT(args.length() == 1);
652 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
653 return proxy->call_trap();
654}
655
656
657RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
658 ASSERT(args.length() == 1);
659 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
660 return proxy->construct_trap();
661}
662
663
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
665 ASSERT(args.length() == 1);
666 CONVERT_CHECKED(JSProxy, proxy, args[0]);
667 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000668 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000669}
670
671
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000672RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
673 HandleScope scope(isolate);
674 ASSERT(args.length() == 1);
675 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
676 ASSERT(weakmap->map()->inobject_properties() == 0);
677 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
678 weakmap->set_table(*table);
679 weakmap->set_next(Smi::FromInt(0));
680 return *weakmap;
681}
682
683
684RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
685 NoHandleAllocation ha;
686 ASSERT(args.length() == 2);
687 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
688 // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
689 // because they cannot be cast to JSObject to get an identity hash code.
690 CONVERT_ARG_CHECKED(JSObject, key, 1);
691 return weakmap->table()->Lookup(*key);
692}
693
694
695RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
696 HandleScope scope(isolate);
697 ASSERT(args.length() == 3);
698 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
699 // TODO(mstarzinger): See Runtime_WeakMapGet above.
700 CONVERT_ARG_CHECKED(JSObject, key, 1);
701 Handle<Object> value(args[2]);
702 Handle<ObjectHashTable> table(weakmap->table());
703 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
704 weakmap->set_table(*new_table);
705 return *value;
706}
707
708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000709RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000710 NoHandleAllocation ha;
711 ASSERT(args.length() == 1);
712 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000713 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000714 return JSObject::cast(obj)->class_name();
715}
716
ager@chromium.org7c537e22008-10-16 08:43:32 +0000717
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000718RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
719 NoHandleAllocation ha;
720 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000721 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
722 Object* obj = input_obj;
723 // We don't expect access checks to be needed on JSProxy objects.
724 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000725 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000726 if (obj->IsAccessCheckNeeded() &&
727 !isolate->MayNamedAccess(JSObject::cast(obj),
728 isolate->heap()->Proto_symbol(),
729 v8::ACCESS_GET)) {
730 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
731 return isolate->heap()->undefined_value();
732 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000733 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000734 } while (obj->IsJSObject() &&
735 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000736 return obj;
737}
738
739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000740RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741 NoHandleAllocation ha;
742 ASSERT(args.length() == 2);
743 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
744 Object* O = args[0];
745 Object* V = args[1];
746 while (true) {
747 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000748 if (prototype->IsNull()) return isolate->heap()->false_value();
749 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000750 V = prototype;
751 }
752}
753
754
ager@chromium.org9085a012009-05-11 19:22:57 +0000755// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000756RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000757 NoHandleAllocation ha;
758 ASSERT(args.length() == 2);
759 CONVERT_CHECKED(JSObject, jsobject, args[0]);
760 CONVERT_CHECKED(JSObject, proto, args[1]);
761
762 // Sanity checks. The old prototype (that we are replacing) could
763 // theoretically be null, but if it is not null then check that we
764 // didn't already install a hidden prototype here.
765 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
766 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
767 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
768
769 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000770 Object* map_or_failure;
771 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
772 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
773 return maybe_map_or_failure;
774 }
775 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000776 Map* new_proto_map = Map::cast(map_or_failure);
777
lrn@chromium.org303ada72010-10-27 09:33:13 +0000778 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
779 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
780 return maybe_map_or_failure;
781 }
782 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000783 Map* new_map = Map::cast(map_or_failure);
784
785 // Set proto's prototype to be the old prototype of the object.
786 new_proto_map->set_prototype(jsobject->GetPrototype());
787 proto->set_map(new_proto_map);
788 new_proto_map->set_is_hidden_prototype();
789
790 // Set the object's prototype to proto.
791 new_map->set_prototype(proto);
792 jsobject->set_map(new_map);
793
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000794 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000795}
796
797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000798RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000799 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000800 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000801 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000802 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803}
804
805
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000806// Recursively traverses hidden prototypes if property is not found
807static void GetOwnPropertyImplementation(JSObject* obj,
808 String* name,
809 LookupResult* result) {
810 obj->LocalLookupRealNamedProperty(name, result);
811
812 if (!result->IsProperty()) {
813 Object* proto = obj->GetPrototype();
814 if (proto->IsJSObject() &&
815 JSObject::cast(proto)->map()->is_hidden_prototype())
816 GetOwnPropertyImplementation(JSObject::cast(proto),
817 name, result);
818 }
819}
820
821
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000822static bool CheckAccessException(LookupResult* result,
823 v8::AccessType access_type) {
824 if (result->type() == CALLBACKS) {
825 Object* callback = result->GetCallbackObject();
826 if (callback->IsAccessorInfo()) {
827 AccessorInfo* info = AccessorInfo::cast(callback);
828 bool can_access =
829 (access_type == v8::ACCESS_HAS &&
830 (info->all_can_read() || info->all_can_write())) ||
831 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
832 (access_type == v8::ACCESS_SET && info->all_can_write());
833 return can_access;
834 }
835 }
836
837 return false;
838}
839
840
841static bool CheckAccess(JSObject* obj,
842 String* name,
843 LookupResult* result,
844 v8::AccessType access_type) {
845 ASSERT(result->IsProperty());
846
847 JSObject* holder = result->holder();
848 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000850 while (true) {
851 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000852 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000853 // Access check callback denied the access, but some properties
854 // can have a special permissions which override callbacks descision
855 // (currently see v8::AccessControl).
856 break;
857 }
858
859 if (current == holder) {
860 return true;
861 }
862
863 current = JSObject::cast(current->GetPrototype());
864 }
865
866 // API callbacks can have per callback access exceptions.
867 switch (result->type()) {
868 case CALLBACKS: {
869 if (CheckAccessException(result, access_type)) {
870 return true;
871 }
872 break;
873 }
874 case INTERCEPTOR: {
875 // If the object has an interceptor, try real named properties.
876 // Overwrite the result to fetch the correct property later.
877 holder->LookupRealNamedProperty(name, result);
878 if (result->IsProperty()) {
879 if (CheckAccessException(result, access_type)) {
880 return true;
881 }
882 }
883 break;
884 }
885 default:
886 break;
887 }
888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000889 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000890 return false;
891}
892
893
894// TODO(1095): we should traverse hidden prototype hierachy as well.
895static bool CheckElementAccess(JSObject* obj,
896 uint32_t index,
897 v8::AccessType access_type) {
898 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000899 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000900 return false;
901 }
902
903 return true;
904}
905
906
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000907// Enumerator used as indices into the array returned from GetOwnProperty
908enum PropertyDescriptorIndices {
909 IS_ACCESSOR_INDEX,
910 VALUE_INDEX,
911 GETTER_INDEX,
912 SETTER_INDEX,
913 WRITABLE_INDEX,
914 ENUMERABLE_INDEX,
915 CONFIGURABLE_INDEX,
916 DESCRIPTOR_SIZE
917};
918
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000919// Returns an array with the property description:
920// if args[1] is not a property on args[0]
921// returns undefined
922// if args[1] is a data property on args[0]
923// [false, value, Writeable, Enumerable, Configurable]
924// if args[1] is an accessor on args[0]
925// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000926RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000927 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 Heap* heap = isolate->heap();
929 HandleScope scope(isolate);
930 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
931 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000932 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000933 CONVERT_ARG_CHECKED(JSObject, obj, 0);
934 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000935
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000936 // This could be an element.
937 uint32_t index;
938 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000939 switch (obj->HasLocalElement(index)) {
940 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000941 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000942
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000943 case JSObject::STRING_CHARACTER_ELEMENT: {
944 // Special handling of string objects according to ECMAScript 5
945 // 15.5.5.2. Note that this might be a string object with elements
946 // other than the actual string value. This is covered by the
947 // subsequent cases.
948 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
949 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000950 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000951
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000952 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000953 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000954 elms->set(WRITABLE_INDEX, heap->false_value());
955 elms->set(ENUMERABLE_INDEX, heap->false_value());
956 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000957 return *desc;
958 }
959
960 case JSObject::INTERCEPTED_ELEMENT:
961 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000963 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000964 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000965 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000966 elms->set(WRITABLE_INDEX, heap->true_value());
967 elms->set(ENUMERABLE_INDEX, heap->true_value());
968 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000969 return *desc;
970 }
971
972 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000973 Handle<JSObject> holder = obj;
974 if (obj->IsJSGlobalProxy()) {
975 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000977 ASSERT(proto->IsJSGlobalObject());
978 holder = Handle<JSObject>(JSObject::cast(proto));
979 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000980 FixedArray* elements = FixedArray::cast(holder->elements());
981 NumberDictionary* dictionary = NULL;
982 if (elements->map() == heap->non_strict_arguments_elements_map()) {
983 dictionary = NumberDictionary::cast(elements->get(1));
984 } else {
985 dictionary = NumberDictionary::cast(elements);
986 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000987 int entry = dictionary->FindEntry(index);
988 ASSERT(entry != NumberDictionary::kNotFound);
989 PropertyDetails details = dictionary->DetailsAt(entry);
990 switch (details.type()) {
991 case CALLBACKS: {
992 // This is an accessor property with getter and/or setter.
993 FixedArray* callbacks =
994 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000995 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000996 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
997 elms->set(GETTER_INDEX, callbacks->get(0));
998 }
999 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1000 elms->set(SETTER_INDEX, callbacks->get(1));
1001 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001002 break;
1003 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001004 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001005 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001006 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001007 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001008 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001009 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001011 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001012 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001013 default:
1014 UNREACHABLE();
1015 break;
1016 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001017 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1018 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001019 return *desc;
1020 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001021 }
1022 }
1023
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001024 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001025 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001026
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001027 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001029 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001030
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001031 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001033 }
1034
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1036 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001037
1038 bool is_js_accessor = (result.type() == CALLBACKS) &&
1039 (result.GetCallbackObject()->IsFixedArray());
1040
1041 if (is_js_accessor) {
1042 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001043 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001044
1045 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1046 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1047 elms->set(GETTER_INDEX, structure->get(0));
1048 }
1049 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1050 elms->set(SETTER_INDEX, structure->get(1));
1051 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001052 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001053 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1054 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001055
1056 PropertyAttributes attrs;
1057 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001058 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001059 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1060 if (!maybe_value->ToObject(&value)) return maybe_value;
1061 }
1062 elms->set(VALUE_INDEX, value);
1063 }
1064
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001065 return *desc;
1066}
1067
1068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001069RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001070 ASSERT(args.length() == 1);
1071 CONVERT_CHECKED(JSObject, obj, args[0]);
1072 return obj->PreventExtensions();
1073}
1074
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001076RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001077 ASSERT(args.length() == 1);
1078 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001079 if (obj->IsJSGlobalProxy()) {
1080 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001082 ASSERT(proto->IsJSGlobalObject());
1083 obj = JSObject::cast(proto);
1084 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001085 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001086}
1087
1088
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001089RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001090 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001092 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1093 CONVERT_ARG_CHECKED(String, pattern, 1);
1094 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001095 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1096 if (result.is_null()) return Failure::Exception();
1097 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098}
1099
1100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001101RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001104 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001105 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106}
1107
1108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001109RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001110 ASSERT(args.length() == 1);
1111 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001112 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114}
1115
1116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001117RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118 ASSERT(args.length() == 2);
1119 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001121 int index = field->value();
1122 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1123 InstanceType type = templ->map()->instance_type();
1124 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1125 type == OBJECT_TEMPLATE_INFO_TYPE);
1126 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001127 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001128 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1129 } else {
1130 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1131 }
1132 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001133}
1134
1135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001136RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001137 ASSERT(args.length() == 1);
1138 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001139 Map* old_map = object->map();
1140 bool needs_access_checks = old_map->is_access_check_needed();
1141 if (needs_access_checks) {
1142 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001143 Object* new_map;
1144 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1145 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1146 }
ager@chromium.org32912102009-01-16 10:38:43 +00001147
1148 Map::cast(new_map)->set_is_access_check_needed(false);
1149 object->set_map(Map::cast(new_map));
1150 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001151 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001152}
1153
1154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001155RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001156 ASSERT(args.length() == 1);
1157 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001158 Map* old_map = object->map();
1159 if (!old_map->is_access_check_needed()) {
1160 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001161 Object* new_map;
1162 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1163 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1164 }
ager@chromium.org32912102009-01-16 10:38:43 +00001165
1166 Map::cast(new_map)->set_is_access_check_needed(true);
1167 object->set_map(Map::cast(new_map));
1168 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001170}
1171
1172
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001173static Failure* ThrowRedeclarationError(Isolate* isolate,
1174 const char* type,
1175 Handle<String> name) {
1176 HandleScope scope(isolate);
1177 Handle<Object> type_handle =
1178 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 Handle<Object> args[2] = { type_handle, name };
1180 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001181 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1182 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183}
1184
1185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001186RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001187 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001188 HandleScope scope(isolate);
1189 Handle<GlobalObject> global = Handle<GlobalObject>(
1190 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191
ager@chromium.org3811b432009-10-28 14:53:37 +00001192 Handle<Context> context = args.at<Context>(0);
1193 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001194 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196 // Traverse the name/value pairs and set the properties.
1197 int length = pairs->length();
1198 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001199 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001201 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202
1203 // We have to declare a global const property. To capture we only
1204 // assign to it when evaluating the assignment for "const x =
1205 // <expr>" the initial value is the hole.
1206 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001207 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001208 if (value->IsUndefined() || is_const_property) {
1209 // Lookup the property in the global object, and don't set the
1210 // value of the variable if the property is already there.
1211 LookupResult lookup;
1212 global->Lookup(*name, &lookup);
1213 if (lookup.IsProperty()) {
1214 // Determine if the property is local by comparing the holder
1215 // against the global object. The information will be used to
1216 // avoid throwing re-declaration errors when declaring
1217 // variables or constants that exist in the prototype chain.
1218 bool is_local = (*global == lookup.holder());
1219 // Get the property attributes and determine if the property is
1220 // read-only.
1221 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1222 bool is_read_only = (attributes & READ_ONLY) != 0;
1223 if (lookup.type() == INTERCEPTOR) {
1224 // If the interceptor says the property is there, we
1225 // just return undefined without overwriting the property.
1226 // Otherwise, we continue to setting the property.
1227 if (attributes != ABSENT) {
1228 // Check if the existing property conflicts with regards to const.
1229 if (is_local && (is_read_only || is_const_property)) {
1230 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001231 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 };
1233 // The property already exists without conflicting: Go to
1234 // the next declaration.
1235 continue;
1236 }
1237 // Fall-through and introduce the absent property by using
1238 // SetProperty.
1239 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001240 // For const properties, we treat a callback with this name
1241 // even in the prototype as a conflicting declaration.
1242 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001243 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001244 }
1245 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246 if (is_local && (is_read_only || is_const_property)) {
1247 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001248 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 }
1250 // The property already exists without conflicting: Go to
1251 // the next declaration.
1252 continue;
1253 }
1254 }
1255 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001256 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001258 Handle<SharedFunctionInfo> shared =
1259 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1262 context,
1263 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264 value = function;
1265 }
1266
1267 LookupResult lookup;
1268 global->LocalLookup(*name, &lookup);
1269
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001270 // There's a local property that we need to overwrite because
1271 // we're either declaring a function or there's an interceptor
1272 // that claims the property is absent.
1273 //
1274 // Check for conflicting re-declarations. We cannot have
1275 // conflicting types in case of intercepted properties because
1276 // they are absent.
1277 if (lookup.IsProperty() &&
1278 (lookup.type() != INTERCEPTOR) &&
1279 (lookup.IsReadOnly() || is_const_property)) {
1280 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001281 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001282 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001284 // Compute the property attributes. According to ECMA-262, section
1285 // 13, page 71, the property must be read-only and
1286 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1287 // property as read-only, so we don't either.
1288 int attr = NONE;
1289 if ((flags & kDeclareGlobalsEvalFlag) == 0) {
1290 attr |= DONT_DELETE;
1291 }
1292 bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
1293 if (is_const_property || (is_native && is_function_declaration)) {
1294 attr |= READ_ONLY;
1295 }
1296
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001297 // Safari does not allow the invocation of callback setters for
1298 // function declarations. To mimic this behavior, we do not allow
1299 // the invocation of setters for function values. This makes a
1300 // difference for global functions with the same names as event
1301 // handlers such as "function onload() {}". Firefox does call the
1302 // onload setter in those case and Safari does not. We follow
1303 // Safari for compatibility.
1304 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001305 // Do not change DONT_DELETE to false from true.
1306 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001307 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001308 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001309 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001311 RETURN_IF_EMPTY_HANDLE(isolate,
1312 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001313 name,
1314 value,
1315 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001317 StrictModeFlag strict_mode =
1318 ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
1319 : kNonStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001320 RETURN_IF_EMPTY_HANDLE(isolate,
1321 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001322 name,
1323 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001324 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001325 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326 }
1327 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001328
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001329 ASSERT(!isolate->has_pending_exception());
1330 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331}
1332
1333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001334RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001335 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001336 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337
ager@chromium.org7c537e22008-10-16 08:43:32 +00001338 CONVERT_ARG_CHECKED(Context, context, 0);
1339 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001340 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001341 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001342 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001344 // Declarations are always done in a function or global context.
1345 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346
1347 int index;
1348 PropertyAttributes attributes;
1349 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001350 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001351 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001352 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353
1354 if (attributes != ABSENT) {
1355 // The name was declared before; check for conflicting
1356 // re-declarations: This is similar to the code in parser.cc in
1357 // the AstBuildingParser::Declare function.
1358 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1359 // Functions are not read-only.
1360 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1361 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001363 }
1364
1365 // Initialize it if necessary.
1366 if (*initial_value != NULL) {
1367 if (index >= 0) {
1368 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001369 // the function context or the arguments object.
1370 if (holder->IsContext()) {
1371 ASSERT(holder.is_identical_to(context));
1372 if (((attributes & READ_ONLY) == 0) ||
1373 context->get(index)->IsTheHole()) {
1374 context->set(index, *initial_value);
1375 }
1376 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001377 // The holder is an arguments object.
1378 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001379 Handle<Object> result = SetElement(arguments, index, initial_value,
1380 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001381 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382 }
1383 } else {
1384 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001385 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001386 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001388 SetProperty(context_ext, name, initial_value,
1389 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 }
1391 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001392
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001394 // The property is not in the function context. It needs to be
1395 // "declared" in the function context's extension context, or in the
1396 // global context.
1397 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001398 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001399 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001400 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001401 } else {
1402 // The function context's extension context does not exists - allocate
1403 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001404 context_ext = isolate->factory()->NewJSObject(
1405 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001406 // And store it in the extension slot.
1407 context->set_extension(*context_ext);
1408 }
1409 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410
ager@chromium.org7c537e22008-10-16 08:43:32 +00001411 // Declare the property by setting it to the initial value if provided,
1412 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1413 // constant declarations).
1414 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001415 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001416 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001417 // Declaring a const context slot is a conflicting declaration if
1418 // there is a callback with that name in a prototype. It is
1419 // allowed to introduce const variables in
1420 // JSContextExtensionObjects. They are treated specially in
1421 // SetProperty and no setters are invoked for those since they are
1422 // not real JSObjects.
1423 if (initial_value->IsTheHole() &&
1424 !context_ext->IsJSContextExtensionObject()) {
1425 LookupResult lookup;
1426 context_ext->Lookup(*name, &lookup);
1427 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001429 }
1430 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001431 RETURN_IF_EMPTY_HANDLE(isolate,
1432 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001433 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001434 }
1435
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001436 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001437}
1438
1439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001440RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001442 // args[0] == name
1443 // args[1] == strict_mode
1444 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445
1446 // Determine if we need to assign to the variable if it already
1447 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001448 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1449 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450
1451 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001452 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001453 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001454 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001455 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456
1457 // According to ECMA-262, section 12.2, page 62, the property must
1458 // not be deletable.
1459 PropertyAttributes attributes = DONT_DELETE;
1460
1461 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001462 // there, there is a property with this name in the prototype chain.
1463 // We follow Safari and Firefox behavior and only set the property
1464 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001465 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001466 // Note that objects can have hidden prototypes, so we need to traverse
1467 // the whole chain of hidden prototypes to do a 'local' lookup.
1468 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001470 while (true) {
1471 real_holder->LocalLookup(*name, &lookup);
1472 if (lookup.IsProperty()) {
1473 // Determine if this is a redeclaration of something read-only.
1474 if (lookup.IsReadOnly()) {
1475 // If we found readonly property on one of hidden prototypes,
1476 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 if (real_holder != isolate->context()->global()) break;
1478 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001479 }
1480
1481 // Determine if this is a redeclaration of an intercepted read-only
1482 // property and figure out if the property exists at all.
1483 bool found = true;
1484 PropertyType type = lookup.type();
1485 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001486 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001487 Handle<JSObject> holder(real_holder);
1488 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1489 real_holder = *holder;
1490 if (intercepted == ABSENT) {
1491 // The interceptor claims the property isn't there. We need to
1492 // make sure to introduce it.
1493 found = false;
1494 } else if ((intercepted & READ_ONLY) != 0) {
1495 // The property is present, but read-only. Since we're trying to
1496 // overwrite it with a variable declaration we must throw a
1497 // re-declaration error. However if we found readonly property
1498 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001499 if (real_holder != isolate->context()->global()) break;
1500 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001501 }
1502 }
1503
1504 if (found && !assign) {
1505 // The global property is there and we're not assigning any value
1506 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001507 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001508 }
1509
1510 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001511 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001512 return real_holder->SetProperty(
1513 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001514 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001515
1516 Object* proto = real_holder->GetPrototype();
1517 if (!proto->IsJSObject())
1518 break;
1519
1520 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1521 break;
1522
1523 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 }
1525
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001526 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001527 if (assign) {
1528 return global->SetProperty(*name, args[2], attributes, strict_mode);
1529 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001530 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531}
1532
1533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001534RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 // All constants are declared with an initial value. The name
1536 // of the constant is the first argument and the initial value
1537 // is the second.
1538 RUNTIME_ASSERT(args.length() == 2);
1539 CONVERT_ARG_CHECKED(String, name, 0);
1540 Handle<Object> value = args.at<Object>(1);
1541
1542 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001543 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544
1545 // According to ECMA-262, section 12.2, page 62, the property must
1546 // not be deletable. Since it's a const, it must be READ_ONLY too.
1547 PropertyAttributes attributes =
1548 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1549
1550 // Lookup the property locally in the global object. If it isn't
1551 // there, we add the property and take special precautions to always
1552 // add it as a local property even in case of callbacks in the
1553 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001554 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 LookupResult lookup;
1556 global->LocalLookup(*name, &lookup);
1557 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001558 return global->SetLocalPropertyIgnoreAttributes(*name,
1559 *value,
1560 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 }
1562
1563 // Determine if this is a redeclaration of something not
1564 // read-only. In case the result is hidden behind an interceptor we
1565 // need to ask it for the property attributes.
1566 if (!lookup.IsReadOnly()) {
1567 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001568 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 }
1570
1571 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1572
1573 // Throw re-declaration error if the intercepted property is present
1574 // but not read-only.
1575 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001576 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 }
1578
1579 // Restore global object from context (in case of GC) and continue
1580 // with setting the value because the property is either absent or
1581 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001582 HandleScope handle_scope(isolate);
1583 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001585 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586 // property through an interceptor and only do it if it's
1587 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001588 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001589 RETURN_IF_EMPTY_HANDLE(isolate,
1590 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001591 name,
1592 value,
1593 attributes,
1594 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 return *value;
1596 }
1597
1598 // Set the value, but only we're assigning the initial value to a
1599 // constant. For now, we determine this by checking if the
1600 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001601 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 PropertyType type = lookup.type();
1603 if (type == FIELD) {
1604 FixedArray* properties = global->properties();
1605 int index = lookup.GetFieldIndex();
1606 if (properties->get(index)->IsTheHole()) {
1607 properties->set(index, *value);
1608 }
1609 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001610 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1611 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 }
1613 } else {
1614 // Ignore re-initialization of constants that have already been
1615 // assigned a function value.
1616 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1617 }
1618
1619 // Use the set value as the result of the operation.
1620 return *value;
1621}
1622
1623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001624RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001625 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 ASSERT(args.length() == 3);
1627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001628 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629 ASSERT(!value->IsTheHole());
1630 CONVERT_ARG_CHECKED(Context, context, 1);
1631 Handle<String> name(String::cast(args[2]));
1632
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001633 // Initializations are always done in a function or global context.
1634 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635
1636 int index;
1637 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001638 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001639 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001640 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001641 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001642
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001643 // In most situations, the property introduced by the const
1644 // declaration should be present in the context extension object.
1645 // However, because declaration and initialization are separate, the
1646 // property might have been deleted (if it was introduced by eval)
1647 // before we reach the initialization point.
1648 //
1649 // Example:
1650 //
1651 // function f() { eval("delete x; const x;"); }
1652 //
1653 // In that case, the initialization behaves like a normal assignment
1654 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001656 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001657 // Property was found in a context. Perform the assignment if we
1658 // found some non-constant or an uninitialized constant.
1659 Handle<Context> context = Handle<Context>::cast(holder);
1660 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1661 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001662 }
1663 } else {
1664 // The holder is an arguments object.
1665 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001666 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001667 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001668 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001669 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001670 }
1671 return *value;
1672 }
1673
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001674 // The property could not be found, we introduce it in the global
1675 // context.
1676 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001677 Handle<JSObject> global = Handle<JSObject>(
1678 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001679 // Strict mode not needed (const disallowed in strict mode).
1680 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001682 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001683 return *value;
1684 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001685
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001686 // The property was present in a context extension object.
1687 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001688
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001689 if (*context_ext == context->extension()) {
1690 // This is the property that was introduced by the const
1691 // declaration. Set it if it hasn't been set before. NOTE: We
1692 // cannot use GetProperty() to get the current value as it
1693 // 'unholes' the value.
1694 LookupResult lookup;
1695 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1696 ASSERT(lookup.IsProperty()); // the property was declared
1697 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1698
1699 PropertyType type = lookup.type();
1700 if (type == FIELD) {
1701 FixedArray* properties = context_ext->properties();
1702 int index = lookup.GetFieldIndex();
1703 if (properties->get(index)->IsTheHole()) {
1704 properties->set(index, *value);
1705 }
1706 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001707 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1708 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001709 }
1710 } else {
1711 // We should not reach here. Any real, named property should be
1712 // either a field or a dictionary slot.
1713 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001714 }
1715 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001716 // The property was found in a different context extension object.
1717 // Set it if it is not a read-only property.
1718 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001719 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001720 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001721 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001722 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001723 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001724 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001725
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001726 return *value;
1727}
1728
1729
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001730RUNTIME_FUNCTION(MaybeObject*,
1731 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001732 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001733 ASSERT(args.length() == 2);
1734 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001735 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001736 if (object->HasFastProperties()) {
1737 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1738 }
1739 return *object;
1740}
1741
1742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001743RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001744 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001745 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001746 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1747 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001748 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001749 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001750 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001751 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001752 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001753 RUNTIME_ASSERT(index >= 0);
1754 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001756 Handle<Object> result = RegExpImpl::Exec(regexp,
1757 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001758 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001759 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001760 if (result.is_null()) return Failure::Exception();
1761 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001762}
1763
1764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001765RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001766 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001767 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001768 if (elements_count < 0 ||
1769 elements_count > FixedArray::kMaxLength ||
1770 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001771 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001772 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001773 Object* new_object;
1774 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001776 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1777 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001778 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1780 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001781 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1782 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001783 {
1784 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001785 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001786 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001787 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001788 }
1789 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001791 array->set_elements(elements);
1792 array->set_length(Smi::FromInt(elements_count));
1793 // Write in-object properties after the length of the array.
1794 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1795 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1796 return array;
1797}
1798
1799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001800RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001801 AssertNoAllocation no_alloc;
1802 ASSERT(args.length() == 5);
1803 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1804 CONVERT_CHECKED(String, source, args[1]);
1805
1806 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001807 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001808
1809 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001810 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001811
1812 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001814
1815 Map* map = regexp->map();
1816 Object* constructor = map->constructor();
1817 if (constructor->IsJSFunction() &&
1818 JSFunction::cast(constructor)->initial_map() == map) {
1819 // If we still have the original map, set in-object properties directly.
1820 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1821 // TODO(lrn): Consider skipping write barrier on booleans as well.
1822 // Both true and false should be in oldspace at all times.
1823 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1824 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1825 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1826 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1827 Smi::FromInt(0),
1828 SKIP_WRITE_BARRIER);
1829 return regexp;
1830 }
1831
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001833 PropertyAttributes final =
1834 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1835 PropertyAttributes writable =
1836 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001837 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001838 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001839 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001840 source,
1841 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001842 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001844 global,
1845 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001846 ASSERT(!result->IsFailure());
1847 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001848 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001849 ignoreCase,
1850 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001851 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001853 multiline,
1854 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001855 ASSERT(!result->IsFailure());
1856 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001858 Smi::FromInt(0),
1859 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001860 ASSERT(!result->IsFailure());
1861 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001862 return regexp;
1863}
1864
1865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001866RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001868 ASSERT(args.length() == 1);
1869 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1870 // This is necessary to enable fast checks for absence of elements
1871 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001872 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001873 return Smi::FromInt(0);
1874}
1875
1876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001877static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1878 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001879 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001880 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001881 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1882 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1883 Handle<JSFunction> optimized =
1884 isolate->factory()->NewFunction(key,
1885 JS_OBJECT_TYPE,
1886 JSObject::kHeaderSize,
1887 code,
1888 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001889 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001890 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001891 return optimized;
1892}
1893
1894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001895RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001897 ASSERT(args.length() == 1);
1898 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1899
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001900 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1901 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1902 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1903 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1904 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1905 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1906 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001907
1908 return *holder;
1909}
1910
1911
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001912RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1913 NoHandleAllocation handle_free;
1914 ASSERT(args.length() == 1);
1915 CONVERT_CHECKED(JSFunction, function, args[0]);
1916 SharedFunctionInfo* shared = function->shared();
1917 if (shared->native() || shared->strict_mode()) {
1918 return isolate->heap()->undefined_value();
1919 }
1920 // Returns undefined for strict or native functions, or
1921 // the associated global receiver for "normal" functions.
1922
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001923 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001924 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001925 return global_context->global()->global_receiver();
1926}
1927
1928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001929RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001930 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001931 ASSERT(args.length() == 4);
1932 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001933 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 Handle<String> pattern = args.at<String>(2);
1935 Handle<String> flags = args.at<String>(3);
1936
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001937 // Get the RegExp function from the context in the literals array.
1938 // This is the RegExp function from the context in which the
1939 // function was created. We do not use the RegExp function from the
1940 // current global context because this might be the RegExp function
1941 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001942 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001943 Handle<JSFunction>(
1944 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001945 // Compute the regular expression literal.
1946 bool has_pending_exception;
1947 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001948 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1949 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001951 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001952 return Failure::Exception();
1953 }
1954 literals->set(index, *regexp);
1955 return *regexp;
1956}
1957
1958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001959RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 NoHandleAllocation ha;
1961 ASSERT(args.length() == 1);
1962
1963 CONVERT_CHECKED(JSFunction, f, args[0]);
1964 return f->shared()->name();
1965}
1966
1967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001968RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001969 NoHandleAllocation ha;
1970 ASSERT(args.length() == 2);
1971
1972 CONVERT_CHECKED(JSFunction, f, args[0]);
1973 CONVERT_CHECKED(String, name, args[1]);
1974 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001975 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001976}
1977
1978
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001979RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1980 NoHandleAllocation ha;
1981 ASSERT(args.length() == 1);
1982 CONVERT_CHECKED(JSFunction, f, args[0]);
1983 return isolate->heap()->ToBoolean(
1984 f->shared()->name_should_print_as_anonymous());
1985}
1986
1987
1988RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1989 NoHandleAllocation ha;
1990 ASSERT(args.length() == 1);
1991 CONVERT_CHECKED(JSFunction, f, args[0]);
1992 f->shared()->set_name_should_print_as_anonymous(true);
1993 return isolate->heap()->undefined_value();
1994}
1995
1996
whesse@chromium.org7b260152011-06-20 15:33:18 +00001997RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1998 HandleScope scope(isolate);
1999 ASSERT(args.length() == 1);
2000
2001 CONVERT_CHECKED(JSFunction, fun, args[0]);
2002 fun->shared()->set_bound(true);
2003 return isolate->heap()->undefined_value();
2004}
2005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002006RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002007 NoHandleAllocation ha;
2008 ASSERT(args.length() == 1);
2009
2010 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002011 Object* obj = f->RemovePrototype();
2012 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002013
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002014 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002015}
2016
2017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002018RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002019 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002020 ASSERT(args.length() == 1);
2021
2022 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002023 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2024 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002025
2026 return *GetScriptWrapper(Handle<Script>::cast(script));
2027}
2028
2029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002030RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002031 NoHandleAllocation ha;
2032 ASSERT(args.length() == 1);
2033
2034 CONVERT_CHECKED(JSFunction, f, args[0]);
2035 return f->shared()->GetSourceCode();
2036}
2037
2038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002039RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040 NoHandleAllocation ha;
2041 ASSERT(args.length() == 1);
2042
2043 CONVERT_CHECKED(JSFunction, fun, args[0]);
2044 int pos = fun->shared()->start_position();
2045 return Smi::FromInt(pos);
2046}
2047
2048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002049RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002050 ASSERT(args.length() == 2);
2051
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002052 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002053 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2054
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002055 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2056
2057 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002058 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002059}
2060
2061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002062RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002063 NoHandleAllocation ha;
2064 ASSERT(args.length() == 2);
2065
2066 CONVERT_CHECKED(JSFunction, fun, args[0]);
2067 CONVERT_CHECKED(String, name, args[1]);
2068 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002069 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002070}
2071
2072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002073RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002074 NoHandleAllocation ha;
2075 ASSERT(args.length() == 2);
2076
2077 CONVERT_CHECKED(JSFunction, fun, args[0]);
2078 CONVERT_CHECKED(Smi, length, args[1]);
2079 fun->shared()->set_length(length->value());
2080 return length;
2081}
2082
2083
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002084// Creates a local, readonly, property called length with the correct
2085// length (when read by the user). This effectively overwrites the
2086// interceptor used to normally provide the length.
2087RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2088 NoHandleAllocation ha;
2089 ASSERT(args.length() == 2);
2090 CONVERT_CHECKED(JSFunction, fun, args[0]);
2091 CONVERT_CHECKED(Smi, length, args[1]);
2092 MaybeObject* maybe_name =
2093 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2094 String* name;
2095 if (!maybe_name->To(&name)) return maybe_name;
2096 PropertyAttributes attr =
2097 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2098 return fun->AddProperty(name, length, attr, kNonStrictMode);
2099}
2100
2101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002102RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002103 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002104 ASSERT(args.length() == 2);
2105
2106 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002107 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002108 Object* obj;
2109 { MaybeObject* maybe_obj =
2110 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2111 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2112 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002113 return args[0]; // return TOS
2114}
2115
2116
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002117RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2118 NoHandleAllocation ha;
2119 RUNTIME_ASSERT(args.length() == 1);
2120 CONVERT_CHECKED(JSFunction, function, args[0]);
2121
2122 MaybeObject* maybe_name =
2123 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2124 String* name;
2125 if (!maybe_name->To(&name)) return maybe_name;
2126
2127 if (function->HasFastProperties()) {
2128 // Construct a new field descriptor with updated attributes.
2129 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2130 int index = instance_desc->Search(name);
2131 ASSERT(index != DescriptorArray::kNotFound);
2132 PropertyDetails details(instance_desc->GetDetails(index));
2133 CallbacksDescriptor new_desc(name,
2134 instance_desc->GetValue(index),
2135 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2136 details.index());
2137 // Construct a new field descriptors array containing the new descriptor.
2138 Object* descriptors_unchecked;
2139 { MaybeObject* maybe_descriptors_unchecked =
2140 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2141 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2142 return maybe_descriptors_unchecked;
2143 }
2144 }
2145 DescriptorArray* new_descriptors =
2146 DescriptorArray::cast(descriptors_unchecked);
2147 // Create a new map featuring the new field descriptors array.
2148 Object* map_unchecked;
2149 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2150 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2151 return maybe_map_unchecked;
2152 }
2153 }
2154 Map* new_map = Map::cast(map_unchecked);
2155 new_map->set_instance_descriptors(new_descriptors);
2156 function->set_map(new_map);
2157 } else { // Dictionary properties.
2158 // Directly manipulate the property details.
2159 int entry = function->property_dictionary()->FindEntry(name);
2160 ASSERT(entry != StringDictionary::kNotFound);
2161 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2162 PropertyDetails new_details(
2163 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2164 details.type(),
2165 details.index());
2166 function->property_dictionary()->DetailsAtPut(entry, new_details);
2167 }
2168 return function;
2169}
2170
2171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002172RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002173 NoHandleAllocation ha;
2174 ASSERT(args.length() == 1);
2175
2176 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002177 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002178}
2179
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002181RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002182 NoHandleAllocation ha;
2183 ASSERT(args.length() == 1);
2184
2185 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002186 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002187}
2188
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002190RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002191 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002192 ASSERT(args.length() == 2);
2193
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002194 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195 Handle<Object> code = args.at<Object>(1);
2196
2197 Handle<Context> context(target->context());
2198
2199 if (!code->IsNull()) {
2200 RUNTIME_ASSERT(code->IsJSFunction());
2201 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002202 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002203
2204 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002205 return Failure::Exception();
2206 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002207 // Since we don't store the source for this we should never
2208 // optimize this.
2209 shared->code()->set_optimizable(false);
2210
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002211 // Set the code, scope info, formal parameter count,
2212 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002213 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002214 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002215 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002216 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002218 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002219 // Set the source code of the target function to undefined.
2220 // SetCode is only used for built-in constructors like String,
2221 // Array, and Object, and some web code
2222 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002223 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002224 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002225 // Clear the optimization hints related to the compiled code as these are no
2226 // longer valid when the code is overwritten.
2227 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002228 context = Handle<Context>(fun->context());
2229
2230 // Make sure we get a fresh copy of the literal vector to avoid
2231 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002232 int number_of_literals = fun->NumberOfLiterals();
2233 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002235 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002236 // Insert the object, regexp and array functions in the literals
2237 // array prefix. These are the functions that will be used when
2238 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002239 literals->set(JSFunction::kLiteralGlobalContextIndex,
2240 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002241 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002242 // It's okay to skip the write barrier here because the literals
2243 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002244 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002245 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002246
2247 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2248 isolate->logger()->LogExistingFunction(
2249 shared, Handle<Code>(shared->code()));
2250 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 }
2252
2253 target->set_context(*context);
2254 return *target;
2255}
2256
2257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002258RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002259 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002260 ASSERT(args.length() == 2);
2261 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002262 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002263 RUNTIME_ASSERT(num >= 0);
2264 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002265 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002266}
2267
2268
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002269MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2270 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002271 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002272 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002273 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002274 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002275 }
2276 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002277 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002278}
2279
2280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002281RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002282 NoHandleAllocation ha;
2283 ASSERT(args.length() == 2);
2284
2285 CONVERT_CHECKED(String, subject, args[0]);
2286 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002287 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002288
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002289 uint32_t i = 0;
2290 if (index->IsSmi()) {
2291 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002292 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002293 i = value;
2294 } else {
2295 ASSERT(index->IsHeapNumber());
2296 double value = HeapNumber::cast(index)->value();
2297 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002298 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002299
2300 // Flatten the string. If someone wants to get a char at an index
2301 // in a cons string, it is likely that more indices will be
2302 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002303 Object* flat;
2304 { MaybeObject* maybe_flat = subject->TryFlatten();
2305 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2306 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002307 subject = String::cast(flat);
2308
2309 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002310 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002311 }
2312
2313 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002314}
2315
2316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002317RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002318 NoHandleAllocation ha;
2319 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002320 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002321}
2322
lrn@chromium.org25156de2010-04-06 13:10:27 +00002323
2324class FixedArrayBuilder {
2325 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002326 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2327 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002328 length_(0) {
2329 // Require a non-zero initial size. Ensures that doubling the size to
2330 // extend the array will work.
2331 ASSERT(initial_capacity > 0);
2332 }
2333
2334 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2335 : array_(backing_store),
2336 length_(0) {
2337 // Require a non-zero initial size. Ensures that doubling the size to
2338 // extend the array will work.
2339 ASSERT(backing_store->length() > 0);
2340 }
2341
2342 bool HasCapacity(int elements) {
2343 int length = array_->length();
2344 int required_length = length_ + elements;
2345 return (length >= required_length);
2346 }
2347
2348 void EnsureCapacity(int elements) {
2349 int length = array_->length();
2350 int required_length = length_ + elements;
2351 if (length < required_length) {
2352 int new_length = length;
2353 do {
2354 new_length *= 2;
2355 } while (new_length < required_length);
2356 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002357 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002358 array_->CopyTo(0, *extended_array, 0, length_);
2359 array_ = extended_array;
2360 }
2361 }
2362
2363 void Add(Object* value) {
2364 ASSERT(length_ < capacity());
2365 array_->set(length_, value);
2366 length_++;
2367 }
2368
2369 void Add(Smi* value) {
2370 ASSERT(length_ < capacity());
2371 array_->set(length_, value);
2372 length_++;
2373 }
2374
2375 Handle<FixedArray> array() {
2376 return array_;
2377 }
2378
2379 int length() {
2380 return length_;
2381 }
2382
2383 int capacity() {
2384 return array_->length();
2385 }
2386
2387 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002388 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 result_array->set_length(Smi::FromInt(length_));
2390 return result_array;
2391 }
2392
2393 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2394 target_array->set_elements(*array_);
2395 target_array->set_length(Smi::FromInt(length_));
2396 return target_array;
2397 }
2398
2399 private:
2400 Handle<FixedArray> array_;
2401 int length_;
2402};
2403
2404
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002405// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002406const int kStringBuilderConcatHelperLengthBits = 11;
2407const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408
2409template <typename schar>
2410static inline void StringBuilderConcatHelper(String*,
2411 schar*,
2412 FixedArray*,
2413 int);
2414
lrn@chromium.org25156de2010-04-06 13:10:27 +00002415typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2416 StringBuilderSubstringLength;
2417typedef BitField<int,
2418 kStringBuilderConcatHelperLengthBits,
2419 kStringBuilderConcatHelperPositionBits>
2420 StringBuilderSubstringPosition;
2421
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002422
2423class ReplacementStringBuilder {
2424 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002425 ReplacementStringBuilder(Heap* heap,
2426 Handle<String> subject,
2427 int estimated_part_count)
2428 : heap_(heap),
2429 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002430 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002431 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002432 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002433 // Require a non-zero initial size. Ensures that doubling the size to
2434 // extend the array will work.
2435 ASSERT(estimated_part_count > 0);
2436 }
2437
lrn@chromium.org25156de2010-04-06 13:10:27 +00002438 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2439 int from,
2440 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002441 ASSERT(from >= 0);
2442 int length = to - from;
2443 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 if (StringBuilderSubstringLength::is_valid(length) &&
2445 StringBuilderSubstringPosition::is_valid(from)) {
2446 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2447 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002448 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002449 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002450 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002451 builder->Add(Smi::FromInt(-length));
2452 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002453 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002454 }
2455
2456
2457 void EnsureCapacity(int elements) {
2458 array_builder_.EnsureCapacity(elements);
2459 }
2460
2461
2462 void AddSubjectSlice(int from, int to) {
2463 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002464 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002465 }
2466
2467
2468 void AddString(Handle<String> string) {
2469 int length = string->length();
2470 ASSERT(length > 0);
2471 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002472 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 is_ascii_ = false;
2474 }
2475 IncrementCharacterCount(length);
2476 }
2477
2478
2479 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002480 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002481 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002482 }
2483
2484 Handle<String> joined_string;
2485 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002486 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002487 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002488 char* char_buffer = seq->GetChars();
2489 StringBuilderConcatHelper(*subject_,
2490 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002491 *array_builder_.array(),
2492 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002493 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494 } else {
2495 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002496 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 uc16* char_buffer = seq->GetChars();
2499 StringBuilderConcatHelper(*subject_,
2500 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002501 *array_builder_.array(),
2502 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002503 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002504 }
2505 return joined_string;
2506 }
2507
2508
2509 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002510 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002511 V8::FatalProcessOutOfMemory("String.replace result too large.");
2512 }
2513 character_count_ += by;
2514 }
2515
lrn@chromium.org25156de2010-04-06 13:10:27 +00002516 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002517 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002518 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002519
lrn@chromium.org25156de2010-04-06 13:10:27 +00002520 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002521 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2522 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002523 }
2524
2525
ager@chromium.org04921a82011-06-27 13:21:41 +00002526 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2527 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002528 }
2529
2530
2531 void AddElement(Object* element) {
2532 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002533 ASSERT(array_builder_.capacity() > array_builder_.length());
2534 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002535 }
2536
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002537 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002538 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002539 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002540 int character_count_;
2541 bool is_ascii_;
2542};
2543
2544
2545class CompiledReplacement {
2546 public:
2547 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002548 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002549
2550 void Compile(Handle<String> replacement,
2551 int capture_count,
2552 int subject_length);
2553
2554 void Apply(ReplacementStringBuilder* builder,
2555 int match_from,
2556 int match_to,
2557 Handle<JSArray> last_match_info);
2558
2559 // Number of distinct parts of the replacement pattern.
2560 int parts() {
2561 return parts_.length();
2562 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002563
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002564 bool simple_hint() {
2565 return simple_hint_;
2566 }
2567
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002568 private:
2569 enum PartType {
2570 SUBJECT_PREFIX = 1,
2571 SUBJECT_SUFFIX,
2572 SUBJECT_CAPTURE,
2573 REPLACEMENT_SUBSTRING,
2574 REPLACEMENT_STRING,
2575
2576 NUMBER_OF_PART_TYPES
2577 };
2578
2579 struct ReplacementPart {
2580 static inline ReplacementPart SubjectMatch() {
2581 return ReplacementPart(SUBJECT_CAPTURE, 0);
2582 }
2583 static inline ReplacementPart SubjectCapture(int capture_index) {
2584 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2585 }
2586 static inline ReplacementPart SubjectPrefix() {
2587 return ReplacementPart(SUBJECT_PREFIX, 0);
2588 }
2589 static inline ReplacementPart SubjectSuffix(int subject_length) {
2590 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2591 }
2592 static inline ReplacementPart ReplacementString() {
2593 return ReplacementPart(REPLACEMENT_STRING, 0);
2594 }
2595 static inline ReplacementPart ReplacementSubString(int from, int to) {
2596 ASSERT(from >= 0);
2597 ASSERT(to > from);
2598 return ReplacementPart(-from, to);
2599 }
2600
2601 // If tag <= 0 then it is the negation of a start index of a substring of
2602 // the replacement pattern, otherwise it's a value from PartType.
2603 ReplacementPart(int tag, int data)
2604 : tag(tag), data(data) {
2605 // Must be non-positive or a PartType value.
2606 ASSERT(tag < NUMBER_OF_PART_TYPES);
2607 }
2608 // Either a value of PartType or a non-positive number that is
2609 // the negation of an index into the replacement string.
2610 int tag;
2611 // The data value's interpretation depends on the value of tag:
2612 // tag == SUBJECT_PREFIX ||
2613 // tag == SUBJECT_SUFFIX: data is unused.
2614 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2615 // tag == REPLACEMENT_SUBSTRING ||
2616 // tag == REPLACEMENT_STRING: data is index into array of substrings
2617 // of the replacement string.
2618 // tag <= 0: Temporary representation of the substring of the replacement
2619 // string ranging over -tag .. data.
2620 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2621 // substring objects.
2622 int data;
2623 };
2624
2625 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002626 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002627 Vector<Char> characters,
2628 int capture_count,
2629 int subject_length) {
2630 int length = characters.length();
2631 int last = 0;
2632 for (int i = 0; i < length; i++) {
2633 Char c = characters[i];
2634 if (c == '$') {
2635 int next_index = i + 1;
2636 if (next_index == length) { // No next character!
2637 break;
2638 }
2639 Char c2 = characters[next_index];
2640 switch (c2) {
2641 case '$':
2642 if (i > last) {
2643 // There is a substring before. Include the first "$".
2644 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2645 last = next_index + 1; // Continue after the second "$".
2646 } else {
2647 // Let the next substring start with the second "$".
2648 last = next_index;
2649 }
2650 i = next_index;
2651 break;
2652 case '`':
2653 if (i > last) {
2654 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2655 }
2656 parts->Add(ReplacementPart::SubjectPrefix());
2657 i = next_index;
2658 last = i + 1;
2659 break;
2660 case '\'':
2661 if (i > last) {
2662 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2663 }
2664 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2665 i = next_index;
2666 last = i + 1;
2667 break;
2668 case '&':
2669 if (i > last) {
2670 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2671 }
2672 parts->Add(ReplacementPart::SubjectMatch());
2673 i = next_index;
2674 last = i + 1;
2675 break;
2676 case '0':
2677 case '1':
2678 case '2':
2679 case '3':
2680 case '4':
2681 case '5':
2682 case '6':
2683 case '7':
2684 case '8':
2685 case '9': {
2686 int capture_ref = c2 - '0';
2687 if (capture_ref > capture_count) {
2688 i = next_index;
2689 continue;
2690 }
2691 int second_digit_index = next_index + 1;
2692 if (second_digit_index < length) {
2693 // Peek ahead to see if we have two digits.
2694 Char c3 = characters[second_digit_index];
2695 if ('0' <= c3 && c3 <= '9') { // Double digits.
2696 int double_digit_ref = capture_ref * 10 + c3 - '0';
2697 if (double_digit_ref <= capture_count) {
2698 next_index = second_digit_index;
2699 capture_ref = double_digit_ref;
2700 }
2701 }
2702 }
2703 if (capture_ref > 0) {
2704 if (i > last) {
2705 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2706 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002707 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002708 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2709 last = next_index + 1;
2710 }
2711 i = next_index;
2712 break;
2713 }
2714 default:
2715 i = next_index;
2716 break;
2717 }
2718 }
2719 }
2720 if (length > last) {
2721 if (last == 0) {
2722 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002723 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002724 } else {
2725 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2726 }
2727 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002728 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002729 }
2730
2731 ZoneList<ReplacementPart> parts_;
2732 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002733 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002734};
2735
2736
2737void CompiledReplacement::Compile(Handle<String> replacement,
2738 int capture_count,
2739 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002740 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002741 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002742 String::FlatContent content = replacement->GetFlatContent();
2743 ASSERT(content.IsFlat());
2744 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002745 simple_hint_ = ParseReplacementPattern(&parts_,
2746 content.ToAsciiVector(),
2747 capture_count,
2748 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002749 } else {
2750 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002751 simple_hint_ = ParseReplacementPattern(&parts_,
2752 content.ToUC16Vector(),
2753 capture_count,
2754 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002755 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002756 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002757 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002758 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002759 int substring_index = 0;
2760 for (int i = 0, n = parts_.length(); i < n; i++) {
2761 int tag = parts_[i].tag;
2762 if (tag <= 0) { // A replacement string slice.
2763 int from = -tag;
2764 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002765 replacement_substrings_.Add(
2766 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002767 parts_[i].tag = REPLACEMENT_SUBSTRING;
2768 parts_[i].data = substring_index;
2769 substring_index++;
2770 } else if (tag == REPLACEMENT_STRING) {
2771 replacement_substrings_.Add(replacement);
2772 parts_[i].data = substring_index;
2773 substring_index++;
2774 }
2775 }
2776}
2777
2778
2779void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2780 int match_from,
2781 int match_to,
2782 Handle<JSArray> last_match_info) {
2783 for (int i = 0, n = parts_.length(); i < n; i++) {
2784 ReplacementPart part = parts_[i];
2785 switch (part.tag) {
2786 case SUBJECT_PREFIX:
2787 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2788 break;
2789 case SUBJECT_SUFFIX: {
2790 int subject_length = part.data;
2791 if (match_to < subject_length) {
2792 builder->AddSubjectSlice(match_to, subject_length);
2793 }
2794 break;
2795 }
2796 case SUBJECT_CAPTURE: {
2797 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002798 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002799 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2800 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2801 if (from >= 0 && to > from) {
2802 builder->AddSubjectSlice(from, to);
2803 }
2804 break;
2805 }
2806 case REPLACEMENT_SUBSTRING:
2807 case REPLACEMENT_STRING:
2808 builder->AddString(replacement_substrings_[part.data]);
2809 break;
2810 default:
2811 UNREACHABLE();
2812 }
2813 }
2814}
2815
2816
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002817void FindAsciiStringIndices(Vector<const char> subject,
2818 char pattern,
2819 ZoneList<int>* indices,
2820 unsigned int limit) {
2821 ASSERT(limit > 0);
2822 // Collect indices of pattern in subject using memchr.
2823 // Stop after finding at most limit values.
2824 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2825 const char* subject_end = subject_start + subject.length();
2826 const char* pos = subject_start;
2827 while (limit > 0) {
2828 pos = reinterpret_cast<const char*>(
2829 memchr(pos, pattern, subject_end - pos));
2830 if (pos == NULL) return;
2831 indices->Add(static_cast<int>(pos - subject_start));
2832 pos++;
2833 limit--;
2834 }
2835}
2836
2837
2838template <typename SubjectChar, typename PatternChar>
2839void FindStringIndices(Isolate* isolate,
2840 Vector<const SubjectChar> subject,
2841 Vector<const PatternChar> pattern,
2842 ZoneList<int>* indices,
2843 unsigned int limit) {
2844 ASSERT(limit > 0);
2845 // Collect indices of pattern in subject.
2846 // Stop after finding at most limit values.
2847 int pattern_length = pattern.length();
2848 int index = 0;
2849 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2850 while (limit > 0) {
2851 index = search.Search(subject, index);
2852 if (index < 0) return;
2853 indices->Add(index);
2854 index += pattern_length;
2855 limit--;
2856 }
2857}
2858
2859
2860void FindStringIndicesDispatch(Isolate* isolate,
2861 String* subject,
2862 String* pattern,
2863 ZoneList<int>* indices,
2864 unsigned int limit) {
2865 {
2866 AssertNoAllocation no_gc;
2867 String::FlatContent subject_content = subject->GetFlatContent();
2868 String::FlatContent pattern_content = pattern->GetFlatContent();
2869 ASSERT(subject_content.IsFlat());
2870 ASSERT(pattern_content.IsFlat());
2871 if (subject_content.IsAscii()) {
2872 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2873 if (pattern_content.IsAscii()) {
2874 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2875 if (pattern_vector.length() == 1) {
2876 FindAsciiStringIndices(subject_vector,
2877 pattern_vector[0],
2878 indices,
2879 limit);
2880 } else {
2881 FindStringIndices(isolate,
2882 subject_vector,
2883 pattern_vector,
2884 indices,
2885 limit);
2886 }
2887 } else {
2888 FindStringIndices(isolate,
2889 subject_vector,
2890 pattern_content.ToUC16Vector(),
2891 indices,
2892 limit);
2893 }
2894 } else {
2895 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
2896 if (pattern->IsAsciiRepresentation()) {
2897 FindStringIndices(isolate,
2898 subject_vector,
2899 pattern_content.ToAsciiVector(),
2900 indices,
2901 limit);
2902 } else {
2903 FindStringIndices(isolate,
2904 subject_vector,
2905 pattern_content.ToUC16Vector(),
2906 indices,
2907 limit);
2908 }
2909 }
2910 }
2911}
2912
2913
2914template<typename ResultSeqString>
2915MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2916 Isolate* isolate,
2917 Handle<String> subject,
2918 Handle<JSRegExp> pattern_regexp,
2919 Handle<String> replacement) {
2920 ASSERT(subject->IsFlat());
2921 ASSERT(replacement->IsFlat());
2922
2923 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2924 ZoneList<int> indices(8);
2925 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2926 String* pattern =
2927 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2928 int subject_len = subject->length();
2929 int pattern_len = pattern->length();
2930 int replacement_len = replacement->length();
2931
2932 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2933
2934 int matches = indices.length();
2935 if (matches == 0) return *subject;
2936
2937 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2938 int subject_pos = 0;
2939 int result_pos = 0;
2940
2941 Handle<ResultSeqString> result;
2942 if (ResultSeqString::kHasAsciiEncoding) {
2943 result = Handle<ResultSeqString>::cast(
2944 isolate->factory()->NewRawAsciiString(result_len));
2945 } else {
2946 result = Handle<ResultSeqString>::cast(
2947 isolate->factory()->NewRawTwoByteString(result_len));
2948 }
2949
2950 for (int i = 0; i < matches; i++) {
2951 // Copy non-matched subject content.
2952 if (subject_pos < indices.at(i)) {
2953 String::WriteToFlat(*subject,
2954 result->GetChars() + result_pos,
2955 subject_pos,
2956 indices.at(i));
2957 result_pos += indices.at(i) - subject_pos;
2958 }
2959
2960 // Replace match.
2961 if (replacement_len > 0) {
2962 String::WriteToFlat(*replacement,
2963 result->GetChars() + result_pos,
2964 0,
2965 replacement_len);
2966 result_pos += replacement_len;
2967 }
2968
2969 subject_pos = indices.at(i) + pattern_len;
2970 }
2971 // Add remaining subject content at the end.
2972 if (subject_pos < subject_len) {
2973 String::WriteToFlat(*subject,
2974 result->GetChars() + result_pos,
2975 subject_pos,
2976 subject_len);
2977 }
2978 return *result;
2979}
2980
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002981
lrn@chromium.org303ada72010-10-27 09:33:13 +00002982MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002983 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002984 String* subject,
2985 JSRegExp* regexp,
2986 String* replacement,
2987 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002988 ASSERT(subject->IsFlat());
2989 ASSERT(replacement->IsFlat());
2990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002991 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002992
2993 int length = subject->length();
2994 Handle<String> subject_handle(subject);
2995 Handle<JSRegExp> regexp_handle(regexp);
2996 Handle<String> replacement_handle(replacement);
2997 Handle<JSArray> last_match_info_handle(last_match_info);
2998 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2999 subject_handle,
3000 0,
3001 last_match_info_handle);
3002 if (match.is_null()) {
3003 return Failure::Exception();
3004 }
3005 if (match->IsNull()) {
3006 return *subject_handle;
3007 }
3008
3009 int capture_count = regexp_handle->CaptureCount();
3010
3011 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003012 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003013 CompiledReplacement compiled_replacement;
3014 compiled_replacement.Compile(replacement_handle,
3015 capture_count,
3016 length);
3017
3018 bool is_global = regexp_handle->GetFlags().is_global();
3019
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003020 // Shortcut for simple non-regexp global replacements
3021 if (is_global &&
3022 regexp->TypeTag() == JSRegExp::ATOM &&
3023 compiled_replacement.simple_hint()) {
3024 if (subject_handle->HasOnlyAsciiChars() &&
3025 replacement_handle->HasOnlyAsciiChars()) {
3026 return StringReplaceStringWithString<SeqAsciiString>(
3027 isolate, subject_handle, regexp_handle, replacement_handle);
3028 } else {
3029 return StringReplaceStringWithString<SeqTwoByteString>(
3030 isolate, subject_handle, regexp_handle, replacement_handle);
3031 }
3032 }
3033
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003034 // Guessing the number of parts that the final result string is built
3035 // from. Global regexps can match any number of times, so we guess
3036 // conservatively.
3037 int expected_parts =
3038 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003039 ReplacementStringBuilder builder(isolate->heap(),
3040 subject_handle,
3041 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003042
3043 // Index of end of last match.
3044 int prev = 0;
3045
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003046 // Number of parts added by compiled replacement plus preceeding
3047 // string and possibly suffix after last match. It is possible for
3048 // all components to use two elements when encoded as two smis.
3049 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003050 bool matched = true;
3051 do {
3052 ASSERT(last_match_info_handle->HasFastElements());
3053 // Increase the capacity of the builder before entering local handle-scope,
3054 // so its internal buffer can safely allocate a new handle if it grows.
3055 builder.EnsureCapacity(parts_added_per_loop);
3056
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003057 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003058 int start, end;
3059 {
3060 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003061 FixedArray* match_info_array =
3062 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003063
3064 ASSERT_EQ(capture_count * 2 + 2,
3065 RegExpImpl::GetLastCaptureCount(match_info_array));
3066 start = RegExpImpl::GetCapture(match_info_array, 0);
3067 end = RegExpImpl::GetCapture(match_info_array, 1);
3068 }
3069
3070 if (prev < start) {
3071 builder.AddSubjectSlice(prev, start);
3072 }
3073 compiled_replacement.Apply(&builder,
3074 start,
3075 end,
3076 last_match_info_handle);
3077 prev = end;
3078
3079 // Only continue checking for global regexps.
3080 if (!is_global) break;
3081
3082 // Continue from where the match ended, unless it was an empty match.
3083 int next = end;
3084 if (start == end) {
3085 next = end + 1;
3086 if (next > length) break;
3087 }
3088
3089 match = RegExpImpl::Exec(regexp_handle,
3090 subject_handle,
3091 next,
3092 last_match_info_handle);
3093 if (match.is_null()) {
3094 return Failure::Exception();
3095 }
3096 matched = !match->IsNull();
3097 } while (matched);
3098
3099 if (prev < length) {
3100 builder.AddSubjectSlice(prev, length);
3101 }
3102
3103 return *(builder.ToString());
3104}
3105
3106
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003107template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003108MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003109 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003110 String* subject,
3111 JSRegExp* regexp,
3112 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003113 ASSERT(subject->IsFlat());
3114
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003115 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003116
3117 Handle<String> subject_handle(subject);
3118 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003119
3120 // Shortcut for simple non-regexp global replacements
3121 if (regexp_handle->GetFlags().is_global() &&
3122 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3123 Handle<String> empty_string_handle(HEAP->empty_string());
3124 if (subject_handle->HasOnlyAsciiChars()) {
3125 return StringReplaceStringWithString<SeqAsciiString>(
3126 isolate, subject_handle, regexp_handle, empty_string_handle);
3127 } else {
3128 return StringReplaceStringWithString<SeqTwoByteString>(
3129 isolate, subject_handle, regexp_handle, empty_string_handle);
3130 }
3131 }
3132
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003133 Handle<JSArray> last_match_info_handle(last_match_info);
3134 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3135 subject_handle,
3136 0,
3137 last_match_info_handle);
3138 if (match.is_null()) return Failure::Exception();
3139 if (match->IsNull()) return *subject_handle;
3140
3141 ASSERT(last_match_info_handle->HasFastElements());
3142
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003143 int start, end;
3144 {
3145 AssertNoAllocation match_info_array_is_not_in_a_handle;
3146 FixedArray* match_info_array =
3147 FixedArray::cast(last_match_info_handle->elements());
3148
3149 start = RegExpImpl::GetCapture(match_info_array, 0);
3150 end = RegExpImpl::GetCapture(match_info_array, 1);
3151 }
3152
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003153 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003154 int new_length = length - (end - start);
3155 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003156 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003157 }
3158 Handle<ResultSeqString> answer;
3159 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003160 answer = Handle<ResultSeqString>::cast(
3161 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003162 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003163 answer = Handle<ResultSeqString>::cast(
3164 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003165 }
3166
3167 // If the regexp isn't global, only match once.
3168 if (!regexp_handle->GetFlags().is_global()) {
3169 if (start > 0) {
3170 String::WriteToFlat(*subject_handle,
3171 answer->GetChars(),
3172 0,
3173 start);
3174 }
3175 if (end < length) {
3176 String::WriteToFlat(*subject_handle,
3177 answer->GetChars() + start,
3178 end,
3179 length);
3180 }
3181 return *answer;
3182 }
3183
3184 int prev = 0; // Index of end of last match.
3185 int next = 0; // Start of next search (prev unless last match was empty).
3186 int position = 0;
3187
3188 do {
3189 if (prev < start) {
3190 // Add substring subject[prev;start] to answer string.
3191 String::WriteToFlat(*subject_handle,
3192 answer->GetChars() + position,
3193 prev,
3194 start);
3195 position += start - prev;
3196 }
3197 prev = end;
3198 next = end;
3199 // Continue from where the match ended, unless it was an empty match.
3200 if (start == end) {
3201 next++;
3202 if (next > length) break;
3203 }
3204 match = RegExpImpl::Exec(regexp_handle,
3205 subject_handle,
3206 next,
3207 last_match_info_handle);
3208 if (match.is_null()) return Failure::Exception();
3209 if (match->IsNull()) break;
3210
3211 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003212 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003213 {
3214 AssertNoAllocation match_info_array_is_not_in_a_handle;
3215 FixedArray* match_info_array =
3216 FixedArray::cast(last_match_info_handle->elements());
3217 start = RegExpImpl::GetCapture(match_info_array, 0);
3218 end = RegExpImpl::GetCapture(match_info_array, 1);
3219 }
3220 } while (true);
3221
3222 if (prev < length) {
3223 // Add substring subject[prev;length] to answer string.
3224 String::WriteToFlat(*subject_handle,
3225 answer->GetChars() + position,
3226 prev,
3227 length);
3228 position += length - prev;
3229 }
3230
3231 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003232 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003233 }
3234
3235 // Shorten string and fill
3236 int string_size = ResultSeqString::SizeFor(position);
3237 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3238 int delta = allocated_string_size - string_size;
3239
3240 answer->set_length(position);
3241 if (delta == 0) return *answer;
3242
3243 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003244 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003245
3246 return *answer;
3247}
3248
3249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003250RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003251 ASSERT(args.length() == 4);
3252
3253 CONVERT_CHECKED(String, subject, args[0]);
3254 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003255 Object* flat_subject;
3256 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3257 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3258 return maybe_flat_subject;
3259 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003260 }
3261 subject = String::cast(flat_subject);
3262 }
3263
3264 CONVERT_CHECKED(String, replacement, args[2]);
3265 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003266 Object* flat_replacement;
3267 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3268 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3269 return maybe_flat_replacement;
3270 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003271 }
3272 replacement = String::cast(flat_replacement);
3273 }
3274
3275 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3276 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3277
3278 ASSERT(last_match_info->HasFastElements());
3279
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003280 if (replacement->length() == 0) {
3281 if (subject->HasOnlyAsciiChars()) {
3282 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003283 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003284 } else {
3285 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003286 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003287 }
3288 }
3289
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003290 return StringReplaceRegExpWithString(isolate,
3291 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003292 regexp,
3293 replacement,
3294 last_match_info);
3295}
3296
3297
ager@chromium.org7c537e22008-10-16 08:43:32 +00003298// Perform string match of pattern on subject, starting at start index.
3299// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003300// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003301int Runtime::StringMatch(Isolate* isolate,
3302 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003303 Handle<String> pat,
3304 int start_index) {
3305 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003306 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003307
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003308 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003309 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003310
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003311 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003312 if (start_index + pattern_length > subject_length) return -1;
3313
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003314 if (!sub->IsFlat()) FlattenString(sub);
3315 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003316
ager@chromium.org7c537e22008-10-16 08:43:32 +00003317 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003318 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003319 String::FlatContent seq_sub = sub->GetFlatContent();
3320 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003321
ager@chromium.org7c537e22008-10-16 08:43:32 +00003322 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003323 if (seq_pat.IsAscii()) {
3324 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3325 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003326 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003327 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003328 pat_vector,
3329 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003330 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003331 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003332 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003333 pat_vector,
3334 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003335 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003336 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3337 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003338 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003339 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003340 pat_vector,
3341 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003342 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003343 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003344 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345 pat_vector,
3346 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003347}
3348
3349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003350RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003351 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003352 ASSERT(args.length() == 3);
3353
ager@chromium.org7c537e22008-10-16 08:43:32 +00003354 CONVERT_ARG_CHECKED(String, sub, 0);
3355 CONVERT_ARG_CHECKED(String, pat, 1);
3356
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003357 Object* index = args[2];
3358 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003359 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003360
ager@chromium.org870a0b62008-11-04 11:43:05 +00003361 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003362 int position =
3363 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003364 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003365}
3366
3367
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003368template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003369static int StringMatchBackwards(Vector<const schar> subject,
3370 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003371 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003372 int pattern_length = pattern.length();
3373 ASSERT(pattern_length >= 1);
3374 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003375
3376 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003377 for (int i = 0; i < pattern_length; i++) {
3378 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003379 if (c > String::kMaxAsciiCharCode) {
3380 return -1;
3381 }
3382 }
3383 }
3384
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003385 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003386 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003387 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003388 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003389 while (j < pattern_length) {
3390 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003391 break;
3392 }
3393 j++;
3394 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003395 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003396 return i;
3397 }
3398 }
3399 return -1;
3400}
3401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003402RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003404 ASSERT(args.length() == 3);
3405
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003406 CONVERT_ARG_CHECKED(String, sub, 0);
3407 CONVERT_ARG_CHECKED(String, pat, 1);
3408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003411 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003412
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003413 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003414 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003416 if (start_index + pat_length > sub_length) {
3417 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003418 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003420 if (pat_length == 0) {
3421 return Smi::FromInt(start_index);
3422 }
3423
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003424 if (!sub->IsFlat()) FlattenString(sub);
3425 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003427 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003428 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3429
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003430 String::FlatContent sub_content = sub->GetFlatContent();
3431 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003432
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003433 if (pat_content.IsAscii()) {
3434 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3435 if (sub_content.IsAscii()) {
3436 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437 pat_vector,
3438 start_index);
3439 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003440 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003441 pat_vector,
3442 start_index);
3443 }
3444 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003445 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3446 if (sub_content.IsAscii()) {
3447 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003448 pat_vector,
3449 start_index);
3450 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003451 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003452 pat_vector,
3453 start_index);
3454 }
3455 }
3456
3457 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003458}
3459
3460
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003461RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003462 NoHandleAllocation ha;
3463 ASSERT(args.length() == 2);
3464
3465 CONVERT_CHECKED(String, str1, args[0]);
3466 CONVERT_CHECKED(String, str2, args[1]);
3467
3468 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003469 int str1_length = str1->length();
3470 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471
3472 // Decide trivial cases without flattening.
3473 if (str1_length == 0) {
3474 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3475 return Smi::FromInt(-str2_length);
3476 } else {
3477 if (str2_length == 0) return Smi::FromInt(str1_length);
3478 }
3479
3480 int end = str1_length < str2_length ? str1_length : str2_length;
3481
3482 // No need to flatten if we are going to find the answer on the first
3483 // character. At this point we know there is at least one character
3484 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003485 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003486 if (d != 0) return Smi::FromInt(d);
3487
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003488 str1->TryFlatten();
3489 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003491 StringInputBuffer& buf1 =
3492 *isolate->runtime_state()->string_locale_compare_buf1();
3493 StringInputBuffer& buf2 =
3494 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003495
3496 buf1.Reset(str1);
3497 buf2.Reset(str2);
3498
3499 for (int i = 0; i < end; i++) {
3500 uint16_t char1 = buf1.GetNext();
3501 uint16_t char2 = buf2.GetNext();
3502 if (char1 != char2) return Smi::FromInt(char1 - char2);
3503 }
3504
3505 return Smi::FromInt(str1_length - str2_length);
3506}
3507
3508
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003509RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003510 NoHandleAllocation ha;
3511 ASSERT(args.length() == 3);
3512
3513 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003514 int start, end;
3515 // We have a fast integer-only case here to avoid a conversion to double in
3516 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003517 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3518 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3519 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3520 start = from_number;
3521 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003522 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003523 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3524 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003525 start = FastD2I(from_number);
3526 end = FastD2I(to_number);
3527 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003528 RUNTIME_ASSERT(end >= start);
3529 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003530 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003531 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003532 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003533}
3534
3535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003536RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003537 ASSERT_EQ(3, args.length());
3538
3539 CONVERT_ARG_CHECKED(String, subject, 0);
3540 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3541 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3542 HandleScope handles;
3543
3544 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3545
3546 if (match.is_null()) {
3547 return Failure::Exception();
3548 }
3549 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003550 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003551 }
3552 int length = subject->length();
3553
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003554 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003555 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003556 int start;
3557 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003558 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003559 {
3560 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003561 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003562 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3563 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3564 }
3565 offsets.Add(start);
3566 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003567 if (start == end) if (++end > length) break;
3568 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003569 if (match.is_null()) {
3570 return Failure::Exception();
3571 }
3572 } while (!match->IsNull());
3573 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003574 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003575 Handle<String> substring = isolate->factory()->
3576 NewSubString(subject, offsets.at(0), offsets.at(1));
3577 elements->set(0, *substring);
3578 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003579 int from = offsets.at(i * 2);
3580 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003581 Handle<String> substring = isolate->factory()->
3582 NewProperSubString(subject, from, to);
3583 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003584 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003585 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003586 result->set_length(Smi::FromInt(matches));
3587 return *result;
3588}
3589
3590
lrn@chromium.org25156de2010-04-06 13:10:27 +00003591// Two smis before and after the match, for very long strings.
3592const int kMaxBuilderEntriesPerRegExpMatch = 5;
3593
3594
3595static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3596 Handle<JSArray> last_match_info,
3597 int match_start,
3598 int match_end) {
3599 // Fill last_match_info with a single capture.
3600 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3601 AssertNoAllocation no_gc;
3602 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3603 RegExpImpl::SetLastCaptureCount(elements, 2);
3604 RegExpImpl::SetLastInput(elements, *subject);
3605 RegExpImpl::SetLastSubject(elements, *subject);
3606 RegExpImpl::SetCapture(elements, 0, match_start);
3607 RegExpImpl::SetCapture(elements, 1, match_end);
3608}
3609
3610
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003611template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003612static bool SearchStringMultiple(Isolate* isolate,
3613 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003614 Vector<const PatternChar> pattern,
3615 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003616 FixedArrayBuilder* builder,
3617 int* match_pos) {
3618 int pos = *match_pos;
3619 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003620 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003621 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003622 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003623 while (pos <= max_search_start) {
3624 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3625 *match_pos = pos;
3626 return false;
3627 }
3628 // Position of end of previous match.
3629 int match_end = pos + pattern_length;
3630 int new_pos = search.Search(subject, match_end);
3631 if (new_pos >= 0) {
3632 // A match.
3633 if (new_pos > match_end) {
3634 ReplacementStringBuilder::AddSubjectSlice(builder,
3635 match_end,
3636 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003637 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003638 pos = new_pos;
3639 builder->Add(pattern_string);
3640 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003641 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003642 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003643 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003644
lrn@chromium.org25156de2010-04-06 13:10:27 +00003645 if (pos < max_search_start) {
3646 ReplacementStringBuilder::AddSubjectSlice(builder,
3647 pos + pattern_length,
3648 subject_length);
3649 }
3650 *match_pos = pos;
3651 return true;
3652}
3653
3654
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003655static bool SearchStringMultiple(Isolate* isolate,
3656 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003657 Handle<String> pattern,
3658 Handle<JSArray> last_match_info,
3659 FixedArrayBuilder* builder) {
3660 ASSERT(subject->IsFlat());
3661 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003662
3663 // Treating as if a previous match was before first character.
3664 int match_pos = -pattern->length();
3665
3666 for (;;) { // Break when search complete.
3667 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3668 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003669 String::FlatContent subject_content = subject->GetFlatContent();
3670 String::FlatContent pattern_content = pattern->GetFlatContent();
3671 if (subject_content.IsAscii()) {
3672 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3673 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003674 if (SearchStringMultiple(isolate,
3675 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003676 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003677 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003678 builder,
3679 &match_pos)) break;
3680 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003681 if (SearchStringMultiple(isolate,
3682 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003683 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003684 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003685 builder,
3686 &match_pos)) break;
3687 }
3688 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003689 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3690 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003691 if (SearchStringMultiple(isolate,
3692 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003693 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003694 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003695 builder,
3696 &match_pos)) break;
3697 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003698 if (SearchStringMultiple(isolate,
3699 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003700 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003701 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003702 builder,
3703 &match_pos)) break;
3704 }
3705 }
3706 }
3707
3708 if (match_pos >= 0) {
3709 SetLastMatchInfoNoCaptures(subject,
3710 last_match_info,
3711 match_pos,
3712 match_pos + pattern->length());
3713 return true;
3714 }
3715 return false; // No matches at all.
3716}
3717
3718
3719static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003720 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003721 Handle<String> subject,
3722 Handle<JSRegExp> regexp,
3723 Handle<JSArray> last_match_array,
3724 FixedArrayBuilder* builder) {
3725 ASSERT(subject->IsFlat());
3726 int match_start = -1;
3727 int match_end = 0;
3728 int pos = 0;
3729 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3730 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3731
3732 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003733 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003734 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003735 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003736
3737 for (;;) { // Break on failure, return on exception.
3738 RegExpImpl::IrregexpResult result =
3739 RegExpImpl::IrregexpExecOnce(regexp,
3740 subject,
3741 pos,
3742 register_vector);
3743 if (result == RegExpImpl::RE_SUCCESS) {
3744 match_start = register_vector[0];
3745 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3746 if (match_end < match_start) {
3747 ReplacementStringBuilder::AddSubjectSlice(builder,
3748 match_end,
3749 match_start);
3750 }
3751 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003752 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003753 if (!first) {
3754 builder->Add(*isolate->factory()->NewProperSubString(subject,
3755 match_start,
3756 match_end));
3757 } else {
3758 builder->Add(*isolate->factory()->NewSubString(subject,
3759 match_start,
3760 match_end));
3761 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003762 if (match_start != match_end) {
3763 pos = match_end;
3764 } else {
3765 pos = match_end + 1;
3766 if (pos > subject_length) break;
3767 }
3768 } else if (result == RegExpImpl::RE_FAILURE) {
3769 break;
3770 } else {
3771 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3772 return result;
3773 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003774 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003775 }
3776
3777 if (match_start >= 0) {
3778 if (match_end < subject_length) {
3779 ReplacementStringBuilder::AddSubjectSlice(builder,
3780 match_end,
3781 subject_length);
3782 }
3783 SetLastMatchInfoNoCaptures(subject,
3784 last_match_array,
3785 match_start,
3786 match_end);
3787 return RegExpImpl::RE_SUCCESS;
3788 } else {
3789 return RegExpImpl::RE_FAILURE; // No matches at all.
3790 }
3791}
3792
3793
3794static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003795 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003796 Handle<String> subject,
3797 Handle<JSRegExp> regexp,
3798 Handle<JSArray> last_match_array,
3799 FixedArrayBuilder* builder) {
3800
3801 ASSERT(subject->IsFlat());
3802 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3803 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3804
3805 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003806 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003807
3808 RegExpImpl::IrregexpResult result =
3809 RegExpImpl::IrregexpExecOnce(regexp,
3810 subject,
3811 0,
3812 register_vector);
3813
3814 int capture_count = regexp->CaptureCount();
3815 int subject_length = subject->length();
3816
3817 // Position to search from.
3818 int pos = 0;
3819 // End of previous match. Differs from pos if match was empty.
3820 int match_end = 0;
3821 if (result == RegExpImpl::RE_SUCCESS) {
3822 // Need to keep a copy of the previous match for creating last_match_info
3823 // at the end, so we have two vectors that we swap between.
3824 OffsetsVector registers2(required_registers);
3825 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003826 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003827 do {
3828 int match_start = register_vector[0];
3829 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3830 if (match_end < match_start) {
3831 ReplacementStringBuilder::AddSubjectSlice(builder,
3832 match_end,
3833 match_start);
3834 }
3835 match_end = register_vector[1];
3836
3837 {
3838 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003839 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003840 // Arguments array to replace function is match, captures, index and
3841 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003842 Handle<FixedArray> elements =
3843 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003844 Handle<String> match;
3845 if (!first) {
3846 match = isolate->factory()->NewProperSubString(subject,
3847 match_start,
3848 match_end);
3849 } else {
3850 match = isolate->factory()->NewSubString(subject,
3851 match_start,
3852 match_end);
3853 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003854 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003855 for (int i = 1; i <= capture_count; i++) {
3856 int start = register_vector[i * 2];
3857 if (start >= 0) {
3858 int end = register_vector[i * 2 + 1];
3859 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003860 Handle<String> substring;
3861 if (!first) {
3862 substring = isolate->factory()->NewProperSubString(subject,
3863 start,
3864 end);
3865 } else {
3866 substring = isolate->factory()->NewSubString(subject, start, end);
3867 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003868 elements->set(i, *substring);
3869 } else {
3870 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003871 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003872 }
3873 }
3874 elements->set(capture_count + 1, Smi::FromInt(match_start));
3875 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003876 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003877 }
3878 // Swap register vectors, so the last successful match is in
3879 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003880 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003881 prev_register_vector = register_vector;
3882 register_vector = tmp;
3883
3884 if (match_end > match_start) {
3885 pos = match_end;
3886 } else {
3887 pos = match_end + 1;
3888 if (pos > subject_length) {
3889 break;
3890 }
3891 }
3892
3893 result = RegExpImpl::IrregexpExecOnce(regexp,
3894 subject,
3895 pos,
3896 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003897 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003898 } while (result == RegExpImpl::RE_SUCCESS);
3899
3900 if (result != RegExpImpl::RE_EXCEPTION) {
3901 // Finished matching, with at least one match.
3902 if (match_end < subject_length) {
3903 ReplacementStringBuilder::AddSubjectSlice(builder,
3904 match_end,
3905 subject_length);
3906 }
3907
3908 int last_match_capture_count = (capture_count + 1) * 2;
3909 int last_match_array_size =
3910 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3911 last_match_array->EnsureSize(last_match_array_size);
3912 AssertNoAllocation no_gc;
3913 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3914 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3915 RegExpImpl::SetLastSubject(elements, *subject);
3916 RegExpImpl::SetLastInput(elements, *subject);
3917 for (int i = 0; i < last_match_capture_count; i++) {
3918 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3919 }
3920 return RegExpImpl::RE_SUCCESS;
3921 }
3922 }
3923 // No matches at all, return failure or exception result directly.
3924 return result;
3925}
3926
3927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003928RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003929 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003931
3932 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003933 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003934 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3935 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3936 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3937
3938 ASSERT(last_match_info->HasFastElements());
3939 ASSERT(regexp->GetFlags().is_global());
3940 Handle<FixedArray> result_elements;
3941 if (result_array->HasFastElements()) {
3942 result_elements =
3943 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003944 }
3945 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003946 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003947 }
3948 FixedArrayBuilder builder(result_elements);
3949
3950 if (regexp->TypeTag() == JSRegExp::ATOM) {
3951 Handle<String> pattern(
3952 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003953 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003954 if (SearchStringMultiple(isolate, subject, pattern,
3955 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003956 return *builder.ToJSArray(result_array);
3957 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003958 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003959 }
3960
3961 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3962
3963 RegExpImpl::IrregexpResult result;
3964 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003965 result = SearchRegExpNoCaptureMultiple(isolate,
3966 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003967 regexp,
3968 last_match_info,
3969 &builder);
3970 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003971 result = SearchRegExpMultiple(isolate,
3972 subject,
3973 regexp,
3974 last_match_info,
3975 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003976 }
3977 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003978 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003979 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3980 return Failure::Exception();
3981}
3982
3983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003984RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 NoHandleAllocation ha;
3986 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003987 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003988 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003990 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003991 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003992 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003993 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003994 // Character array used for conversion.
3995 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 return isolate->heap()->
3997 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003998 }
3999 }
4000
4001 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004002 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004004 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004005 }
4006 if (isinf(value)) {
4007 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004008 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004010 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004012 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004013 MaybeObject* result =
4014 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 DeleteArray(str);
4016 return result;
4017}
4018
4019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004020RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 NoHandleAllocation ha;
4022 ASSERT(args.length() == 2);
4023
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004024 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004026 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 }
4028 if (isinf(value)) {
4029 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004030 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004032 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004034 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004035 int f = FastD2I(f_number);
4036 RUNTIME_ASSERT(f >= 0);
4037 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 MaybeObject* res =
4039 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004041 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042}
4043
4044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004045RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 NoHandleAllocation ha;
4047 ASSERT(args.length() == 2);
4048
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004049 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004051 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004052 }
4053 if (isinf(value)) {
4054 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004055 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004057 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004058 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004059 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 int f = FastD2I(f_number);
4061 RUNTIME_ASSERT(f >= -1 && f <= 20);
4062 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004063 MaybeObject* res =
4064 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004066 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067}
4068
4069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004071 NoHandleAllocation ha;
4072 ASSERT(args.length() == 2);
4073
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004074 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004076 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 }
4078 if (isinf(value)) {
4079 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004082 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004084 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004085 int f = FastD2I(f_number);
4086 RUNTIME_ASSERT(f >= 1 && f <= 21);
4087 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004088 MaybeObject* res =
4089 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004091 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092}
4093
4094
4095// Returns a single character string where first character equals
4096// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004097static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004098 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004099 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004100 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004101 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004103 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104}
4105
4106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004107MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4108 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004109 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004110 // Handle [] indexing on Strings
4111 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004112 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4113 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 }
4115
4116 // Handle [] indexing on String objects
4117 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004118 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4119 Handle<Object> result =
4120 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4121 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004122 }
4123
4124 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004125 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126 return prototype->GetElement(index);
4127 }
4128
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004129 return GetElement(object, index);
4130}
4131
4132
lrn@chromium.org303ada72010-10-27 09:33:13 +00004133MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134 return object->GetElement(index);
4135}
4136
4137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004138MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4139 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004140 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004141 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004142
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004144 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004145 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004146 isolate->factory()->NewTypeError("non_object_property_load",
4147 HandleVector(args, 2));
4148 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004149 }
4150
4151 // Check if the given key is an array index.
4152 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004153 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004154 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155 }
4156
4157 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004158 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004159 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004160 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004162 bool has_pending_exception = false;
4163 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004164 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004166 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004167 }
4168
ager@chromium.org32912102009-01-16 10:38:43 +00004169 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170 // the element if so.
4171 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004172 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004174 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175 }
4176}
4177
4178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004179RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180 NoHandleAllocation ha;
4181 ASSERT(args.length() == 2);
4182
4183 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004184 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187}
4188
4189
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004190// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004191RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004192 NoHandleAllocation ha;
4193 ASSERT(args.length() == 2);
4194
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004195 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004196 // itself.
4197 //
4198 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004199 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004200 // global proxy object never has properties. This is the case
4201 // because the global proxy object forwards everything to its hidden
4202 // prototype including local lookups.
4203 //
4204 // Additionally, we need to make sure that we do not cache results
4205 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004206 if (args[0]->IsJSObject() &&
4207 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00004208 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004209 args[1]->IsString()) {
4210 JSObject* receiver = JSObject::cast(args[0]);
4211 String* key = String::cast(args[1]);
4212 if (receiver->HasFastProperties()) {
4213 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004214 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004215 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4216 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004217 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004218 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004219 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004220 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004221 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004222 LookupResult result;
4223 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00004224 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004225 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004226 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004227 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004228 }
4229 } else {
4230 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004231 StringDictionary* dictionary = receiver->property_dictionary();
4232 int entry = dictionary->FindEntry(key);
4233 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004234 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004235 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004236 if (!receiver->IsGlobalObject()) return value;
4237 value = JSGlobalPropertyCell::cast(value)->value();
4238 if (!value->IsTheHole()) return value;
4239 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004240 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004241 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004242 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4243 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004244 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004245 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004246 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004247 if (index >= 0 && index < str->length()) {
4248 Handle<Object> result = GetCharAt(str, index);
4249 return *result;
4250 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004251 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004252
4253 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004254 return Runtime::GetObjectProperty(isolate,
4255 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004256 args.at<Object>(1));
4257}
4258
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004259// Implements part of 8.12.9 DefineOwnProperty.
4260// There are 3 cases that lead here:
4261// Step 4b - define a new accessor property.
4262// Steps 9c & 12 - replace an existing data property with an accessor property.
4263// Step 12 - update an existing accessor property with an accessor or generic
4264// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004265RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004266 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004267 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004268 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4269 CONVERT_CHECKED(String, name, args[1]);
4270 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004271 Object* fun = args[3];
4272 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004273 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4274 int unchecked = flag_attr->value();
4275 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4276 RUNTIME_ASSERT(!obj->IsNull());
4277 LookupResult result;
4278 obj->LocalLookupRealNamedProperty(name, &result);
4279
4280 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4281 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4282 // delete it to avoid running into trouble in DefineAccessor, which
4283 // handles this incorrectly if the property is readonly (does nothing)
4284 if (result.IsProperty() &&
4285 (result.type() == FIELD || result.type() == NORMAL
4286 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004287 Object* ok;
4288 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004289 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004290 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4291 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004292 }
4293 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4294}
4295
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004296// Implements part of 8.12.9 DefineOwnProperty.
4297// There are 3 cases that lead here:
4298// Step 4a - define a new data property.
4299// Steps 9b & 12 - replace an existing accessor property with a data property.
4300// Step 12 - update an existing data property with a data or generic
4301// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004302RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004303 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004304 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004305 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4306 CONVERT_ARG_CHECKED(String, name, 1);
4307 Handle<Object> obj_value = args.at<Object>(2);
4308
4309 CONVERT_CHECKED(Smi, flag, args[3]);
4310 int unchecked = flag->value();
4311 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4312
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004313 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4314
4315 // Check if this is an element.
4316 uint32_t index;
4317 bool is_element = name->AsArrayIndex(&index);
4318
4319 // Special case for elements if any of the flags are true.
4320 // If elements are in fast case we always implicitly assume that:
4321 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4322 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4323 is_element) {
4324 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004325 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004326 // We do not need to do access checks here since these has already
4327 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004328 Handle<Object> proto(js_object->GetPrototype());
4329 // If proxy is detached, ignore the assignment. Alternatively,
4330 // we could throw an exception.
4331 if (proto->IsNull()) return *obj_value;
4332 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004333 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004334
4335 // Don't allow element properties to be redefined on objects with external
4336 // array elements.
4337 if (js_object->HasExternalArrayElements()) {
4338 Handle<Object> args[2] = { js_object, name };
4339 Handle<Object> error =
4340 isolate->factory()->NewTypeError("redef_external_array_element",
4341 HandleVector(args, 2));
4342 return isolate->Throw(*error);
4343 }
4344
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004345 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004346 // Make sure that we never go back to fast case.
4347 dictionary->set_requires_slow_elements();
4348 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004349 Handle<NumberDictionary> extended_dictionary =
4350 NumberDictionarySet(dictionary, index, obj_value, details);
4351 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004352 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004353 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4354 } else {
4355 js_object->set_elements(*extended_dictionary);
4356 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004357 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004358 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004359 }
4360
ager@chromium.org5c838252010-02-19 08:53:10 +00004361 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004362 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004363
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004364 // To be compatible with safari we do not change the value on API objects
4365 // in defineProperty. Firefox disagrees here, and actually changes the value.
4366 if (result.IsProperty() &&
4367 (result.type() == CALLBACKS) &&
4368 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004369 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004370 }
4371
ager@chromium.org5c838252010-02-19 08:53:10 +00004372 // Take special care when attributes are different and there is already
4373 // a property. For simplicity we normalize the property which enables us
4374 // to not worry about changing the instance_descriptor and creating a new
4375 // map. The current version of SetObjectProperty does not handle attributes
4376 // correctly in the case where a property is a field and is reset with
4377 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004378 if (result.IsProperty() &&
4379 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004380 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004381 if (js_object->IsJSGlobalProxy()) {
4382 // Since the result is a property, the prototype will exist so
4383 // we don't have to check for null.
4384 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004385 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004386 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004387 // Use IgnoreAttributes version since a readonly property may be
4388 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004389 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4390 *obj_value,
4391 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004392 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004393
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004394 return Runtime::ForceSetObjectProperty(isolate,
4395 js_object,
4396 name,
4397 obj_value,
4398 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004399}
4400
4401
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004402// Special case for elements if any of the flags are true.
4403// If elements are in fast case we always implicitly assume that:
4404// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4405static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4406 Handle<JSObject> js_object,
4407 uint32_t index,
4408 Handle<Object> value,
4409 PropertyAttributes attr) {
4410 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004411 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004412 // Make sure that we never go back to fast case.
4413 dictionary->set_requires_slow_elements();
4414 PropertyDetails details = PropertyDetails(attr, NORMAL);
4415 Handle<NumberDictionary> extended_dictionary =
4416 NumberDictionarySet(dictionary, index, value, details);
4417 if (*extended_dictionary != *dictionary) {
4418 js_object->set_elements(*extended_dictionary);
4419 }
4420 return *value;
4421}
4422
4423
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004424MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4425 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004426 Handle<Object> key,
4427 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004428 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004429 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004431
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004432 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004433 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004434 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004435 isolate->factory()->NewTypeError("non_object_property_store",
4436 HandleVector(args, 2));
4437 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 }
4439
4440 // If the object isn't a JavaScript object, we ignore the store.
4441 if (!object->IsJSObject()) return *value;
4442
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004443 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4444
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445 // Check if the given key is an array index.
4446 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004447 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4449 // of a string using [] notation. We need to support this too in
4450 // JavaScript.
4451 // In the case of a String object we just need to redirect the assignment to
4452 // the underlying string if the index is in range. Since the underlying
4453 // string does nothing with the assignment then we can ignore such
4454 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004455 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004456 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004457 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004458
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004459 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4460 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4461 }
4462
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004463 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004464 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465 return *value;
4466 }
4467
4468 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004469 Handle<Object> result;
4470 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004471 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4472 return NormalizeObjectSetElement(isolate,
4473 js_object,
4474 index,
4475 value,
4476 attr);
4477 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004478 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004480 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004481 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004482 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004484 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 return *value;
4486 }
4487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 bool has_pending_exception = false;
4490 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4491 if (has_pending_exception) return Failure::Exception();
4492 Handle<String> name = Handle<String>::cast(converted);
4493
4494 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004495 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004496 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004497 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 }
4499}
4500
4501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004502MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4503 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004504 Handle<Object> key,
4505 Handle<Object> value,
4506 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004507 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004508
4509 // Check if the given key is an array index.
4510 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004511 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004512 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4513 // of a string using [] notation. We need to support this too in
4514 // JavaScript.
4515 // In the case of a String object we just need to redirect the assignment to
4516 // the underlying string if the index is in range. Since the underlying
4517 // string does nothing with the assignment then we can ignore such
4518 // assignments.
4519 if (js_object->IsStringObjectWithCharacterAt(index)) {
4520 return *value;
4521 }
4522
whesse@chromium.org7b260152011-06-20 15:33:18 +00004523 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004524 }
4525
4526 if (key->IsString()) {
4527 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004528 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004529 } else {
4530 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004531 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004532 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4533 *value,
4534 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004535 }
4536 }
4537
4538 // Call-back into JavaScript to convert the key to a string.
4539 bool has_pending_exception = false;
4540 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4541 if (has_pending_exception) return Failure::Exception();
4542 Handle<String> name = Handle<String>::cast(converted);
4543
4544 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004545 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004546 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004547 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004548 }
4549}
4550
4551
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004553 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004554 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004555 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004556
4557 // Check if the given key is an array index.
4558 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004559 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004560 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4561 // characters of a string using [] notation. In the case of a
4562 // String object we just need to redirect the deletion to the
4563 // underlying string if the index is in range. Since the
4564 // underlying string does nothing with the deletion, we can ignore
4565 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004566 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004567 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004568 }
4569
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004570 return JSObject::cast(*receiver)->DeleteElement(
4571 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004572 }
4573
4574 Handle<String> key_string;
4575 if (key->IsString()) {
4576 key_string = Handle<String>::cast(key);
4577 } else {
4578 // Call-back into JavaScript to convert the key to a string.
4579 bool has_pending_exception = false;
4580 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4581 if (has_pending_exception) return Failure::Exception();
4582 key_string = Handle<String>::cast(converted);
4583 }
4584
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004585 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004586 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004587}
4588
4589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004590RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004591 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004592 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593
4594 Handle<Object> object = args.at<Object>(0);
4595 Handle<Object> key = args.at<Object>(1);
4596 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004597 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004598 RUNTIME_ASSERT(
4599 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004601 PropertyAttributes attributes =
4602 static_cast<PropertyAttributes>(unchecked_attributes);
4603
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004604 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004605 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004606 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004607 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4608 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004609 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004611
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004612 return Runtime::SetObjectProperty(isolate,
4613 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004614 key,
4615 value,
4616 attributes,
4617 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618}
4619
4620
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004621// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004622// This is used to decide if we should transform null and undefined
4623// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004624RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004625 NoHandleAllocation ha;
4626 RUNTIME_ASSERT(args.length() == 1);
4627
4628 Handle<Object> object = args.at<Object>(0);
4629
4630 if (object->IsJSFunction()) {
4631 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004632 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004633 }
4634 return isolate->heap()->undefined_value();
4635}
4636
4637
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004638// Set a local property, even if it is READ_ONLY. If the property does not
4639// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004640RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004641 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004642 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004643 CONVERT_CHECKED(JSObject, object, args[0]);
4644 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004645 // Compute attributes.
4646 PropertyAttributes attributes = NONE;
4647 if (args.length() == 4) {
4648 CONVERT_CHECKED(Smi, value_obj, args[3]);
4649 int unchecked_value = value_obj->value();
4650 // Only attribute bits should be set.
4651 RUNTIME_ASSERT(
4652 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4653 attributes = static_cast<PropertyAttributes>(unchecked_value);
4654 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004655
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004656 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004657 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658}
4659
4660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004661RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004662 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004663 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004664
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004665 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004666 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004667 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004668 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004669 ? JSReceiver::STRICT_DELETION
4670 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004671}
4672
4673
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004674static Object* HasLocalPropertyImplementation(Isolate* isolate,
4675 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004676 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004677 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004678 // Handle hidden prototypes. If there's a hidden prototype above this thing
4679 // then we have to check it for properties, because they are supposed to
4680 // look like they are on this object.
4681 Handle<Object> proto(object->GetPrototype());
4682 if (proto->IsJSObject() &&
4683 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004684 return HasLocalPropertyImplementation(isolate,
4685 Handle<JSObject>::cast(proto),
4686 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004687 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004688 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004689}
4690
4691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004692RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693 NoHandleAllocation ha;
4694 ASSERT(args.length() == 2);
4695 CONVERT_CHECKED(String, key, args[1]);
4696
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004697 uint32_t index;
4698 const bool key_is_array_index = key->AsArrayIndex(&index);
4699
ager@chromium.org9085a012009-05-11 19:22:57 +00004700 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004702 if (obj->IsJSObject()) {
4703 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004704 // Fast case: either the key is a real named property or it is not
4705 // an array index and there are no interceptors or hidden
4706 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004708 Map* map = object->map();
4709 if (!key_is_array_index &&
4710 !map->has_named_interceptor() &&
4711 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4712 return isolate->heap()->false_value();
4713 }
4714 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004715 HandleScope scope(isolate);
4716 return HasLocalPropertyImplementation(isolate,
4717 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004718 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004719 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004721 String* string = String::cast(obj);
4722 if (index < static_cast<uint32_t>(string->length())) {
4723 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724 }
4725 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004726 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727}
4728
4729
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004730RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004731 NoHandleAllocation na;
4732 ASSERT(args.length() == 2);
4733
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004734 // Only JS receivers can have properties.
4735 if (args[0]->IsJSReceiver()) {
4736 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004737 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004738 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004739 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004740 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004741}
4742
4743
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004744RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004745 NoHandleAllocation na;
4746 ASSERT(args.length() == 2);
4747
4748 // Only JS objects can have elements.
4749 if (args[0]->IsJSObject()) {
4750 JSObject* object = JSObject::cast(args[0]);
4751 CONVERT_CHECKED(Smi, index_obj, args[1]);
4752 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004753 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004754 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756}
4757
4758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004759RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760 NoHandleAllocation ha;
4761 ASSERT(args.length() == 2);
4762
4763 CONVERT_CHECKED(JSObject, object, args[0]);
4764 CONVERT_CHECKED(String, key, args[1]);
4765
4766 uint32_t index;
4767 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004768 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 }
4770
ager@chromium.org870a0b62008-11-04 11:43:05 +00004771 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004772 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004773}
4774
4775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004776RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004777 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004778 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004779 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004780 return *GetKeysFor(object);
4781}
4782
4783
4784// Returns either a FixedArray as Runtime_GetPropertyNames,
4785// or, if the given object has an enum cache that contains
4786// all enumerable properties of the object and its prototypes
4787// have none, the map of the object. This is used to speed up
4788// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004789RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790 ASSERT(args.length() == 1);
4791
4792 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4793
4794 if (raw_object->IsSimpleEnum()) return raw_object->map();
4795
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004796 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004798 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4799 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004800
4801 // Test again, since cache may have been built by preceding call.
4802 if (object->IsSimpleEnum()) return object->map();
4803
4804 return *content;
4805}
4806
4807
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004808// Find the length of the prototype chain that is to to handled as one. If a
4809// prototype object is hidden it is to be viewed as part of the the object it
4810// is prototype for.
4811static int LocalPrototypeChainLength(JSObject* obj) {
4812 int count = 1;
4813 Object* proto = obj->GetPrototype();
4814 while (proto->IsJSObject() &&
4815 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4816 count++;
4817 proto = JSObject::cast(proto)->GetPrototype();
4818 }
4819 return count;
4820}
4821
4822
4823// Return the names of the local named properties.
4824// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004826 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004827 ASSERT(args.length() == 1);
4828 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004829 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004830 }
4831 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4832
4833 // Skip the global proxy as it has no properties and always delegates to the
4834 // real global object.
4835 if (obj->IsJSGlobalProxy()) {
4836 // Only collect names if access is permitted.
4837 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004838 !isolate->MayNamedAccess(*obj,
4839 isolate->heap()->undefined_value(),
4840 v8::ACCESS_KEYS)) {
4841 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4842 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004843 }
4844 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4845 }
4846
4847 // Find the number of objects making up this.
4848 int length = LocalPrototypeChainLength(*obj);
4849
4850 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004851 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004852 int total_property_count = 0;
4853 Handle<JSObject> jsproto = obj;
4854 for (int i = 0; i < length; i++) {
4855 // Only collect names if access is permitted.
4856 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004857 !isolate->MayNamedAccess(*jsproto,
4858 isolate->heap()->undefined_value(),
4859 v8::ACCESS_KEYS)) {
4860 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4861 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004862 }
4863 int n;
4864 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4865 local_property_count[i] = n;
4866 total_property_count += n;
4867 if (i < length - 1) {
4868 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4869 }
4870 }
4871
4872 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004873 Handle<FixedArray> names =
4874 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004875
4876 // Get the property names.
4877 jsproto = obj;
4878 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004879 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004880 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004881 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4882 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004883 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004884 proto_with_hidden_properties++;
4885 }
4886 if (i < length - 1) {
4887 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4888 }
4889 }
4890
4891 // Filter out name of hidden propeties object.
4892 if (proto_with_hidden_properties > 0) {
4893 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004894 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004895 names->length() - proto_with_hidden_properties);
4896 int dest_pos = 0;
4897 for (int i = 0; i < total_property_count; i++) {
4898 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004899 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004900 continue;
4901 }
4902 names->set(dest_pos++, name);
4903 }
4904 }
4905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004906 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004907}
4908
4909
4910// Return the names of the local indexed properties.
4911// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004912RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004913 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004914 ASSERT(args.length() == 1);
4915 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004916 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004917 }
4918 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4919
4920 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004921 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004922 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004923 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004924}
4925
4926
4927// Return information on whether an object has a named or indexed interceptor.
4928// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004929RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004930 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004931 ASSERT(args.length() == 1);
4932 if (!args[0]->IsJSObject()) {
4933 return Smi::FromInt(0);
4934 }
4935 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4936
4937 int result = 0;
4938 if (obj->HasNamedInterceptor()) result |= 2;
4939 if (obj->HasIndexedInterceptor()) result |= 1;
4940
4941 return Smi::FromInt(result);
4942}
4943
4944
4945// Return property names from named interceptor.
4946// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004947RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004948 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004949 ASSERT(args.length() == 1);
4950 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4951
4952 if (obj->HasNamedInterceptor()) {
4953 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4954 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4955 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004956 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004957}
4958
4959
4960// Return element names from indexed interceptor.
4961// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004962RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004963 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004964 ASSERT(args.length() == 1);
4965 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4966
4967 if (obj->HasIndexedInterceptor()) {
4968 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4969 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4970 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004971 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004972}
4973
4974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004975RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004976 ASSERT_EQ(args.length(), 1);
4977 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004978 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004979 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004980
4981 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004982 // Do access checks before going to the global object.
4983 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004985 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004986 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4987 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004988 }
4989
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004990 Handle<Object> proto(object->GetPrototype());
4991 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004992 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004993 object = Handle<JSObject>::cast(proto);
4994 }
4995
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004996 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4997 LOCAL_ONLY);
4998 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4999 // property array and since the result is mutable we have to create
5000 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005001 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005002 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005003 for (int i = 0; i < length; i++) {
5004 Object* entry = contents->get(i);
5005 if (entry->IsString()) {
5006 copy->set(i, entry);
5007 } else {
5008 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009 HandleScope scope(isolate);
5010 Handle<Object> entry_handle(entry, isolate);
5011 Handle<Object> entry_str =
5012 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005013 copy->set(i, *entry_str);
5014 }
5015 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005017}
5018
5019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005020RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005021 NoHandleAllocation ha;
5022 ASSERT(args.length() == 1);
5023
5024 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005025 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005026 it.AdvanceToArgumentsFrame();
5027 JavaScriptFrame* frame = it.frame();
5028
5029 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005030 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005031
5032 // Try to convert the key to an index. If successful and within
5033 // index return the the argument from the frame.
5034 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005035 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005036 return frame->GetParameter(index);
5037 }
5038
5039 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005040 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005041 bool exception = false;
5042 Handle<Object> converted =
5043 Execution::ToString(args.at<Object>(0), &exception);
5044 if (exception) return Failure::Exception();
5045 Handle<String> key = Handle<String>::cast(converted);
5046
5047 // Try to convert the string key into an array index.
5048 if (key->AsArrayIndex(&index)) {
5049 if (index < n) {
5050 return frame->GetParameter(index);
5051 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005053 }
5054 }
5055
5056 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005057 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5058 if (key->Equals(isolate->heap()->callee_symbol())) {
5059 Object* function = frame->function();
5060 if (function->IsJSFunction() &&
5061 JSFunction::cast(function)->shared()->strict_mode()) {
5062 return isolate->Throw(*isolate->factory()->NewTypeError(
5063 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5064 }
5065 return function;
5066 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005067
5068 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005069 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005070}
5071
5072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005073RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005074 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005075
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005076 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005077 Handle<Object> object = args.at<Object>(0);
5078 if (object->IsJSObject()) {
5079 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005080 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005081 MaybeObject* ok = js_object->TransformToFastProperties(0);
5082 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005083 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005084 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005085 return *object;
5086}
5087
5088
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005089RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005090 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005091
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005092 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005093 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005094 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005095 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005096 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005097 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005098 return *object;
5099}
5100
5101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005102RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005103 NoHandleAllocation ha;
5104 ASSERT(args.length() == 1);
5105
5106 return args[0]->ToBoolean();
5107}
5108
5109
5110// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5111// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005112RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113 NoHandleAllocation ha;
5114
5115 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005116 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005117 HeapObject* heap_obj = HeapObject::cast(obj);
5118
5119 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005120 if (heap_obj->map()->is_undetectable()) {
5121 return isolate->heap()->undefined_symbol();
5122 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005123
5124 InstanceType instance_type = heap_obj->map()->instance_type();
5125 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005126 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005127 }
5128
5129 switch (instance_type) {
5130 case ODDBALL_TYPE:
5131 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005132 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005133 }
5134 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005135 return FLAG_harmony_typeof
5136 ? isolate->heap()->null_symbol()
5137 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005138 }
5139 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005140 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005141 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005142 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005143 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005144 default:
5145 // For any kind of object not handled above, the spec rule for
5146 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005147 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005148 }
5149}
5150
5151
lrn@chromium.org25156de2010-04-06 13:10:27 +00005152static bool AreDigits(const char*s, int from, int to) {
5153 for (int i = from; i < to; i++) {
5154 if (s[i] < '0' || s[i] > '9') return false;
5155 }
5156
5157 return true;
5158}
5159
5160
5161static int ParseDecimalInteger(const char*s, int from, int to) {
5162 ASSERT(to - from < 10); // Overflow is not possible.
5163 ASSERT(from < to);
5164 int d = s[from] - '0';
5165
5166 for (int i = from + 1; i < to; i++) {
5167 d = 10 * d + (s[i] - '0');
5168 }
5169
5170 return d;
5171}
5172
5173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005174RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175 NoHandleAllocation ha;
5176 ASSERT(args.length() == 1);
5177 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005178 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005179
5180 // Fast case: short integer or some sorts of junk values.
5181 int len = subject->length();
5182 if (subject->IsSeqAsciiString()) {
5183 if (len == 0) return Smi::FromInt(0);
5184
5185 char const* data = SeqAsciiString::cast(subject)->GetChars();
5186 bool minus = (data[0] == '-');
5187 int start_pos = (minus ? 1 : 0);
5188
5189 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005190 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005191 } else if (data[start_pos] > '9') {
5192 // Fast check for a junk value. A valid string may start from a
5193 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5194 // the 'I' character ('Infinity'). All of that have codes not greater than
5195 // '9' except 'I'.
5196 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005197 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005198 }
5199 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5200 // The maximal/minimal smi has 10 digits. If the string has less digits we
5201 // know it will fit into the smi-data type.
5202 int d = ParseDecimalInteger(data, start_pos, len);
5203 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005204 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005205 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005206 } else if (!subject->HasHashCode() &&
5207 len <= String::kMaxArrayIndexSize &&
5208 (len == 1 || data[0] != '0')) {
5209 // String hash is not calculated yet but all the data are present.
5210 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005211 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005212#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005213 subject->Hash(); // Force hash calculation.
5214 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5215 static_cast<int>(hash));
5216#endif
5217 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005218 }
5219 return Smi::FromInt(d);
5220 }
5221 }
5222
5223 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005224 return isolate->heap()->NumberFromDouble(
5225 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226}
5227
5228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005229RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005230 NoHandleAllocation ha;
5231 ASSERT(args.length() == 1);
5232
5233 CONVERT_CHECKED(JSArray, codes, args[0]);
5234 int length = Smi::cast(codes->length())->value();
5235
5236 // Check if the string can be ASCII.
5237 int i;
5238 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005239 Object* element;
5240 { MaybeObject* maybe_element = codes->GetElement(i);
5241 // We probably can't get an exception here, but just in order to enforce
5242 // the checking of inputs in the runtime calls we check here.
5243 if (!maybe_element->ToObject(&element)) return maybe_element;
5244 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005245 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5246 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5247 break;
5248 }
5249
lrn@chromium.org303ada72010-10-27 09:33:13 +00005250 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005252 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005253 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005254 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005255 }
5256
lrn@chromium.org303ada72010-10-27 09:33:13 +00005257 Object* object = NULL;
5258 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005259 String* result = String::cast(object);
5260 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005261 Object* element;
5262 { MaybeObject* maybe_element = codes->GetElement(i);
5263 if (!maybe_element->ToObject(&element)) return maybe_element;
5264 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005265 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005266 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267 }
5268 return result;
5269}
5270
5271
5272// kNotEscaped is generated by the following:
5273//
5274// #!/bin/perl
5275// for (my $i = 0; $i < 256; $i++) {
5276// print "\n" if $i % 16 == 0;
5277// my $c = chr($i);
5278// my $escaped = 1;
5279// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5280// print $escaped ? "0, " : "1, ";
5281// }
5282
5283
5284static bool IsNotEscaped(uint16_t character) {
5285 // Only for 8 bit characters, the rest are always escaped (in a different way)
5286 ASSERT(character < 256);
5287 static const char kNotEscaped[256] = {
5288 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5290 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5291 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5292 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5293 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5294 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5295 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5296 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5297 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5298 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5299 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5300 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5301 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5302 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5303 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5304 };
5305 return kNotEscaped[character] != 0;
5306}
5307
5308
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005309RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005310 const char hex_chars[] = "0123456789ABCDEF";
5311 NoHandleAllocation ha;
5312 ASSERT(args.length() == 1);
5313 CONVERT_CHECKED(String, source, args[0]);
5314
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005315 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005316
5317 int escaped_length = 0;
5318 int length = source->length();
5319 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005320 Access<StringInputBuffer> buffer(
5321 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005322 buffer->Reset(source);
5323 while (buffer->has_more()) {
5324 uint16_t character = buffer->GetNext();
5325 if (character >= 256) {
5326 escaped_length += 6;
5327 } else if (IsNotEscaped(character)) {
5328 escaped_length++;
5329 } else {
5330 escaped_length += 3;
5331 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005332 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005333 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005334 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005335 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005336 return Failure::OutOfMemoryException();
5337 }
5338 }
5339 }
5340 // No length change implies no change. Return original string if no change.
5341 if (escaped_length == length) {
5342 return source;
5343 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005344 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005345 { MaybeObject* maybe_o =
5346 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005347 if (!maybe_o->ToObject(&o)) return maybe_o;
5348 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005349 String* destination = String::cast(o);
5350 int dest_position = 0;
5351
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005352 Access<StringInputBuffer> buffer(
5353 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005354 buffer->Rewind();
5355 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005356 uint16_t chr = buffer->GetNext();
5357 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005358 destination->Set(dest_position, '%');
5359 destination->Set(dest_position+1, 'u');
5360 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5361 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5362 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5363 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005364 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005365 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005366 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005367 dest_position++;
5368 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005369 destination->Set(dest_position, '%');
5370 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5371 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005372 dest_position += 3;
5373 }
5374 }
5375 return destination;
5376}
5377
5378
5379static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5380 static const signed char kHexValue['g'] = {
5381 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5382 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5383 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5384 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5385 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5386 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5387 -1, 10, 11, 12, 13, 14, 15 };
5388
5389 if (character1 > 'f') return -1;
5390 int hi = kHexValue[character1];
5391 if (hi == -1) return -1;
5392 if (character2 > 'f') return -1;
5393 int lo = kHexValue[character2];
5394 if (lo == -1) return -1;
5395 return (hi << 4) + lo;
5396}
5397
5398
ager@chromium.org870a0b62008-11-04 11:43:05 +00005399static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005400 int i,
5401 int length,
5402 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005403 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005404 int32_t hi = 0;
5405 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005406 if (character == '%' &&
5407 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005408 source->Get(i + 1) == 'u' &&
5409 (hi = TwoDigitHex(source->Get(i + 2),
5410 source->Get(i + 3))) != -1 &&
5411 (lo = TwoDigitHex(source->Get(i + 4),
5412 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005413 *step = 6;
5414 return (hi << 8) + lo;
5415 } else if (character == '%' &&
5416 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005417 (lo = TwoDigitHex(source->Get(i + 1),
5418 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005419 *step = 3;
5420 return lo;
5421 } else {
5422 *step = 1;
5423 return character;
5424 }
5425}
5426
5427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005428RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005429 NoHandleAllocation ha;
5430 ASSERT(args.length() == 1);
5431 CONVERT_CHECKED(String, source, args[0]);
5432
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005433 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005434
5435 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005436 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005437
5438 int unescaped_length = 0;
5439 for (int i = 0; i < length; unescaped_length++) {
5440 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005441 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005442 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005443 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005444 i += step;
5445 }
5446
5447 // No length change implies no change. Return original string if no change.
5448 if (unescaped_length == length)
5449 return source;
5450
lrn@chromium.org303ada72010-10-27 09:33:13 +00005451 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005452 { MaybeObject* maybe_o =
5453 ascii ?
5454 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5455 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005456 if (!maybe_o->ToObject(&o)) return maybe_o;
5457 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005458 String* destination = String::cast(o);
5459
5460 int dest_position = 0;
5461 for (int i = 0; i < length; dest_position++) {
5462 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005463 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005464 i += step;
5465 }
5466 return destination;
5467}
5468
5469
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005470static const unsigned int kQuoteTableLength = 128u;
5471
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005472static const int kJsonQuotesCharactersPerEntry = 8;
5473static const char* const JsonQuotes =
5474 "\\u0000 \\u0001 \\u0002 \\u0003 "
5475 "\\u0004 \\u0005 \\u0006 \\u0007 "
5476 "\\b \\t \\n \\u000b "
5477 "\\f \\r \\u000e \\u000f "
5478 "\\u0010 \\u0011 \\u0012 \\u0013 "
5479 "\\u0014 \\u0015 \\u0016 \\u0017 "
5480 "\\u0018 \\u0019 \\u001a \\u001b "
5481 "\\u001c \\u001d \\u001e \\u001f "
5482 " ! \\\" # "
5483 "$ % & ' "
5484 "( ) * + "
5485 ", - . / "
5486 "0 1 2 3 "
5487 "4 5 6 7 "
5488 "8 9 : ; "
5489 "< = > ? "
5490 "@ A B C "
5491 "D E F G "
5492 "H I J K "
5493 "L M N O "
5494 "P Q R S "
5495 "T U V W "
5496 "X Y Z [ "
5497 "\\\\ ] ^ _ "
5498 "` a b c "
5499 "d e f g "
5500 "h i j k "
5501 "l m n o "
5502 "p q r s "
5503 "t u v w "
5504 "x y z { "
5505 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005506
5507
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005508// For a string that is less than 32k characters it should always be
5509// possible to allocate it in new space.
5510static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5511
5512
5513// Doing JSON quoting cannot make the string more than this many times larger.
5514static const int kJsonQuoteWorstCaseBlowup = 6;
5515
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005516static const int kSpaceForQuotesAndComma = 3;
5517static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005518
5519// Covers the entire ASCII range (all other characters are unchanged by JSON
5520// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005521static const byte JsonQuoteLengths[kQuoteTableLength] = {
5522 6, 6, 6, 6, 6, 6, 6, 6,
5523 2, 2, 2, 6, 2, 2, 6, 6,
5524 6, 6, 6, 6, 6, 6, 6, 6,
5525 6, 6, 6, 6, 6, 6, 6, 6,
5526 1, 1, 2, 1, 1, 1, 1, 1,
5527 1, 1, 1, 1, 1, 1, 1, 1,
5528 1, 1, 1, 1, 1, 1, 1, 1,
5529 1, 1, 1, 1, 1, 1, 1, 1,
5530 1, 1, 1, 1, 1, 1, 1, 1,
5531 1, 1, 1, 1, 1, 1, 1, 1,
5532 1, 1, 1, 1, 1, 1, 1, 1,
5533 1, 1, 1, 1, 2, 1, 1, 1,
5534 1, 1, 1, 1, 1, 1, 1, 1,
5535 1, 1, 1, 1, 1, 1, 1, 1,
5536 1, 1, 1, 1, 1, 1, 1, 1,
5537 1, 1, 1, 1, 1, 1, 1, 1,
5538};
5539
5540
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005541template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005542MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005543
5544
5545template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005546MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5547 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005548}
5549
5550
5551template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005552MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5553 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005554}
5555
5556
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005557template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005558static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5559 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005560 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005561 const Char* read_cursor = characters.start();
5562 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005563 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005564 int quoted_length = kSpaceForQuotes;
5565 while (read_cursor < end) {
5566 Char c = *(read_cursor++);
5567 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5568 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005569 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005570 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005571 }
5572 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005573 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5574 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005575 Object* new_object;
5576 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005577 return new_alloc;
5578 }
5579 StringType* new_string = StringType::cast(new_object);
5580
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005581 Char* write_cursor = reinterpret_cast<Char*>(
5582 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005583 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005584 *(write_cursor++) = '"';
5585
5586 read_cursor = characters.start();
5587 while (read_cursor < end) {
5588 Char c = *(read_cursor++);
5589 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5590 *(write_cursor++) = c;
5591 } else {
5592 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5593 const char* replacement = JsonQuotes +
5594 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5595 for (int i = 0; i < len; i++) {
5596 *write_cursor++ = *replacement++;
5597 }
5598 }
5599 }
5600 *(write_cursor++) = '"';
5601 return new_string;
5602}
5603
5604
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005605template <typename SinkChar, typename SourceChar>
5606static inline SinkChar* WriteQuoteJsonString(
5607 Isolate* isolate,
5608 SinkChar* write_cursor,
5609 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005610 // SinkChar is only char if SourceChar is guaranteed to be char.
5611 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005612 const SourceChar* read_cursor = characters.start();
5613 const SourceChar* end = read_cursor + characters.length();
5614 *(write_cursor++) = '"';
5615 while (read_cursor < end) {
5616 SourceChar c = *(read_cursor++);
5617 if (sizeof(SourceChar) > 1u &&
5618 static_cast<unsigned>(c) >= kQuoteTableLength) {
5619 *(write_cursor++) = static_cast<SinkChar>(c);
5620 } else {
5621 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5622 const char* replacement = JsonQuotes +
5623 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5624 write_cursor[0] = replacement[0];
5625 if (len > 1) {
5626 write_cursor[1] = replacement[1];
5627 if (len > 2) {
5628 ASSERT(len == 6);
5629 write_cursor[2] = replacement[2];
5630 write_cursor[3] = replacement[3];
5631 write_cursor[4] = replacement[4];
5632 write_cursor[5] = replacement[5];
5633 }
5634 }
5635 write_cursor += len;
5636 }
5637 }
5638 *(write_cursor++) = '"';
5639 return write_cursor;
5640}
5641
5642
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005643template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005644static MaybeObject* QuoteJsonString(Isolate* isolate,
5645 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005646 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005647 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005648 int worst_case_length =
5649 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005650 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005651 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005652 }
5653
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005654 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5655 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005656 Object* new_object;
5657 if (!new_alloc->ToObject(&new_object)) {
5658 return new_alloc;
5659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005660 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005661 // Even if our string is small enough to fit in new space we still have to
5662 // handle it being allocated in old space as may happen in the third
5663 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5664 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005665 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005666 }
5667 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005668 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005669
5670 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5671 Char* write_cursor = reinterpret_cast<Char*>(
5672 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005673 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005674 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5675 write_cursor,
5676 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005677 int final_length = static_cast<int>(
5678 write_cursor - reinterpret_cast<Char*>(
5679 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005680 isolate->heap()->new_space()->
5681 template ShrinkStringAtAllocationBoundary<StringType>(
5682 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005683 return new_string;
5684}
5685
5686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005687RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005688 NoHandleAllocation ha;
5689 CONVERT_CHECKED(String, str, args[0]);
5690 if (!str->IsFlat()) {
5691 MaybeObject* try_flatten = str->TryFlatten();
5692 Object* flat;
5693 if (!try_flatten->ToObject(&flat)) {
5694 return try_flatten;
5695 }
5696 str = String::cast(flat);
5697 ASSERT(str->IsFlat());
5698 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005699 String::FlatContent flat = str->GetFlatContent();
5700 ASSERT(flat.IsFlat());
5701 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005702 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005703 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005704 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005705 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005706 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005707 }
5708}
5709
5710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005711RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005712 NoHandleAllocation ha;
5713 CONVERT_CHECKED(String, str, args[0]);
5714 if (!str->IsFlat()) {
5715 MaybeObject* try_flatten = str->TryFlatten();
5716 Object* flat;
5717 if (!try_flatten->ToObject(&flat)) {
5718 return try_flatten;
5719 }
5720 str = String::cast(flat);
5721 ASSERT(str->IsFlat());
5722 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005723 String::FlatContent flat = str->GetFlatContent();
5724 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005725 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005726 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005727 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005728 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005729 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005730 }
5731}
5732
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005733
5734template <typename Char, typename StringType>
5735static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5736 FixedArray* array,
5737 int worst_case_length) {
5738 int length = array->length();
5739
5740 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5741 worst_case_length);
5742 Object* new_object;
5743 if (!new_alloc->ToObject(&new_object)) {
5744 return new_alloc;
5745 }
5746 if (!isolate->heap()->new_space()->Contains(new_object)) {
5747 // Even if our string is small enough to fit in new space we still have to
5748 // handle it being allocated in old space as may happen in the third
5749 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5750 // CEntryStub::GenerateCore.
5751 return isolate->heap()->undefined_value();
5752 }
5753 AssertNoAllocation no_gc;
5754 StringType* new_string = StringType::cast(new_object);
5755 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5756
5757 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5758 Char* write_cursor = reinterpret_cast<Char*>(
5759 new_string->address() + SeqAsciiString::kHeaderSize);
5760 *(write_cursor++) = '[';
5761 for (int i = 0; i < length; i++) {
5762 if (i != 0) *(write_cursor++) = ',';
5763 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005764 String::FlatContent content = str->GetFlatContent();
5765 ASSERT(content.IsFlat());
5766 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005767 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5768 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005769 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005770 } else {
5771 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5772 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005773 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005774 }
5775 }
5776 *(write_cursor++) = ']';
5777
5778 int final_length = static_cast<int>(
5779 write_cursor - reinterpret_cast<Char*>(
5780 new_string->address() + SeqAsciiString::kHeaderSize));
5781 isolate->heap()->new_space()->
5782 template ShrinkStringAtAllocationBoundary<StringType>(
5783 new_string, final_length);
5784 return new_string;
5785}
5786
5787
5788RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5789 NoHandleAllocation ha;
5790 ASSERT(args.length() == 1);
5791 CONVERT_CHECKED(JSArray, array, args[0]);
5792
5793 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5794 FixedArray* elements = FixedArray::cast(array->elements());
5795 int n = elements->length();
5796 bool ascii = true;
5797 int total_length = 0;
5798
5799 for (int i = 0; i < n; i++) {
5800 Object* elt = elements->get(i);
5801 if (!elt->IsString()) return isolate->heap()->undefined_value();
5802 String* element = String::cast(elt);
5803 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5804 total_length += element->length();
5805 if (ascii && element->IsTwoByteRepresentation()) {
5806 ascii = false;
5807 }
5808 }
5809
5810 int worst_case_length =
5811 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5812 + total_length * kJsonQuoteWorstCaseBlowup;
5813
5814 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5815 return isolate->heap()->undefined_value();
5816 }
5817
5818 if (ascii) {
5819 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5820 elements,
5821 worst_case_length);
5822 } else {
5823 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5824 elements,
5825 worst_case_length);
5826 }
5827}
5828
5829
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005830RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005831 NoHandleAllocation ha;
5832
5833 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005834 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005835
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005836 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005837
lrn@chromium.org25156de2010-04-06 13:10:27 +00005838 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005839 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005840 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005841}
5842
5843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005844RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005845 NoHandleAllocation ha;
5846 CONVERT_CHECKED(String, str, args[0]);
5847
5848 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005849 double value = StringToDouble(isolate->unicode_cache(),
5850 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005851
5852 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005853 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854}
5855
5856
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005857template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005858MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005859 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005860 String* s,
5861 int length,
5862 int input_string_length,
5863 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005864 // We try this twice, once with the assumption that the result is no longer
5865 // than the input and, if that assumption breaks, again with the exact
5866 // length. This may not be pretty, but it is nicer than what was here before
5867 // and I hereby claim my vaffel-is.
5868 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005869 // Allocate the resulting string.
5870 //
5871 // NOTE: This assumes that the upper/lower case of an ascii
5872 // character is also ascii. This is currently the case, but it
5873 // might break in the future if we implement more context and locale
5874 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005875 Object* o;
5876 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005877 ? isolate->heap()->AllocateRawAsciiString(length)
5878 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005879 if (!maybe_o->ToObject(&o)) return maybe_o;
5880 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005881 String* result = String::cast(o);
5882 bool has_changed_character = false;
5883
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005884 // Convert all characters to upper case, assuming that they will fit
5885 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005886 Access<StringInputBuffer> buffer(
5887 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005888 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005889 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005890 // We can assume that the string is not empty
5891 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005892 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005893 bool has_next = buffer->has_more();
5894 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895 int char_length = mapping->get(current, next, chars);
5896 if (char_length == 0) {
5897 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005898 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005899 i++;
5900 } else if (char_length == 1) {
5901 // Common case: converting the letter resulted in one character.
5902 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005903 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005904 has_changed_character = true;
5905 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005906 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005907 // We've assumed that the result would be as long as the
5908 // input but here is a character that converts to several
5909 // characters. No matter, we calculate the exact length
5910 // of the result and try the whole thing again.
5911 //
5912 // Note that this leaves room for optimization. We could just
5913 // memcpy what we already have to the result string. Also,
5914 // the result string is the last object allocated we could
5915 // "realloc" it and probably, in the vast majority of cases,
5916 // extend the existing string to be able to hold the full
5917 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005918 int next_length = 0;
5919 if (has_next) {
5920 next_length = mapping->get(next, 0, chars);
5921 if (next_length == 0) next_length = 1;
5922 }
5923 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924 while (buffer->has_more()) {
5925 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005926 // NOTE: we use 0 as the next character here because, while
5927 // the next character may affect what a character converts to,
5928 // it does not in any case affect the length of what it convert
5929 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005930 int char_length = mapping->get(current, 0, chars);
5931 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005932 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005933 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005934 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005935 return Failure::OutOfMemoryException();
5936 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005938 // Try again with the real length.
5939 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940 } else {
5941 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005942 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005943 i++;
5944 }
5945 has_changed_character = true;
5946 }
5947 current = next;
5948 }
5949 if (has_changed_character) {
5950 return result;
5951 } else {
5952 // If we didn't actually change anything in doing the conversion
5953 // we simple return the result and let the converted string
5954 // become garbage; there is no reason to keep two identical strings
5955 // alive.
5956 return s;
5957 }
5958}
5959
5960
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005961namespace {
5962
lrn@chromium.org303ada72010-10-27 09:33:13 +00005963static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5964
5965
5966// Given a word and two range boundaries returns a word with high bit
5967// set in every byte iff the corresponding input byte was strictly in
5968// the range (m, n). All the other bits in the result are cleared.
5969// This function is only useful when it can be inlined and the
5970// boundaries are statically known.
5971// Requires: all bytes in the input word and the boundaries must be
5972// ascii (less than 0x7F).
5973static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5974 // Every byte in an ascii string is less than or equal to 0x7F.
5975 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5976 // Use strict inequalities since in edge cases the function could be
5977 // further simplified.
5978 ASSERT(0 < m && m < n && n < 0x7F);
5979 // Has high bit set in every w byte less than n.
5980 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5981 // Has high bit set in every w byte greater than m.
5982 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5983 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5984}
5985
5986
5987enum AsciiCaseConversion {
5988 ASCII_TO_LOWER,
5989 ASCII_TO_UPPER
5990};
5991
5992
5993template <AsciiCaseConversion dir>
5994struct FastAsciiConverter {
5995 static bool Convert(char* dst, char* src, int length) {
5996#ifdef DEBUG
5997 char* saved_dst = dst;
5998 char* saved_src = src;
5999#endif
6000 // We rely on the distance between upper and lower case letters
6001 // being a known power of 2.
6002 ASSERT('a' - 'A' == (1 << 5));
6003 // Boundaries for the range of input characters than require conversion.
6004 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6005 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6006 bool changed = false;
6007 char* const limit = src + length;
6008#ifdef V8_HOST_CAN_READ_UNALIGNED
6009 // Process the prefix of the input that requires no conversion one
6010 // (machine) word at a time.
6011 while (src <= limit - sizeof(uintptr_t)) {
6012 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6013 if (AsciiRangeMask(w, lo, hi) != 0) {
6014 changed = true;
6015 break;
6016 }
6017 *reinterpret_cast<uintptr_t*>(dst) = w;
6018 src += sizeof(uintptr_t);
6019 dst += sizeof(uintptr_t);
6020 }
6021 // Process the remainder of the input performing conversion when
6022 // required one word at a time.
6023 while (src <= limit - sizeof(uintptr_t)) {
6024 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6025 uintptr_t m = AsciiRangeMask(w, lo, hi);
6026 // The mask has high (7th) bit set in every byte that needs
6027 // conversion and we know that the distance between cases is
6028 // 1 << 5.
6029 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6030 src += sizeof(uintptr_t);
6031 dst += sizeof(uintptr_t);
6032 }
6033#endif
6034 // Process the last few bytes of the input (or the whole input if
6035 // unaligned access is not supported).
6036 while (src < limit) {
6037 char c = *src;
6038 if (lo < c && c < hi) {
6039 c ^= (1 << 5);
6040 changed = true;
6041 }
6042 *dst = c;
6043 ++src;
6044 ++dst;
6045 }
6046#ifdef DEBUG
6047 CheckConvert(saved_dst, saved_src, length, changed);
6048#endif
6049 return changed;
6050 }
6051
6052#ifdef DEBUG
6053 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6054 bool expected_changed = false;
6055 for (int i = 0; i < length; i++) {
6056 if (dst[i] == src[i]) continue;
6057 expected_changed = true;
6058 if (dir == ASCII_TO_LOWER) {
6059 ASSERT('A' <= src[i] && src[i] <= 'Z');
6060 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6061 } else {
6062 ASSERT(dir == ASCII_TO_UPPER);
6063 ASSERT('a' <= src[i] && src[i] <= 'z');
6064 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6065 }
6066 }
6067 ASSERT(expected_changed == changed);
6068 }
6069#endif
6070};
6071
6072
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006073struct ToLowerTraits {
6074 typedef unibrow::ToLowercase UnibrowConverter;
6075
lrn@chromium.org303ada72010-10-27 09:33:13 +00006076 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006077};
6078
6079
6080struct ToUpperTraits {
6081 typedef unibrow::ToUppercase UnibrowConverter;
6082
lrn@chromium.org303ada72010-10-27 09:33:13 +00006083 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006084};
6085
6086} // namespace
6087
6088
6089template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006090MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006091 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006092 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006093 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006094 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006095 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006096 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006097
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006098 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006099 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006100 if (length == 0) return s;
6101
6102 // Simpler handling of ascii strings.
6103 //
6104 // NOTE: This assumes that the upper/lower case of an ascii
6105 // character is also ascii. This is currently the case, but it
6106 // might break in the future if we implement more context and locale
6107 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006108 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006109 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006110 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006111 if (!maybe_o->ToObject(&o)) return maybe_o;
6112 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006113 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006114 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006115 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006116 return has_changed_character ? result : s;
6117 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006118
lrn@chromium.org303ada72010-10-27 09:33:13 +00006119 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006120 { MaybeObject* maybe_answer =
6121 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006122 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6123 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006124 if (answer->IsSmi()) {
6125 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006126 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006127 ConvertCaseHelper(isolate,
6128 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006129 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6130 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006131 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006132 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006133}
6134
6135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006136RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006137 return ConvertCase<ToLowerTraits>(
6138 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006139}
6140
6141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006142RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006143 return ConvertCase<ToUpperTraits>(
6144 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006145}
6146
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006147
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006148static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
6149 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
6150}
6151
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006153RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006154 NoHandleAllocation ha;
6155 ASSERT(args.length() == 3);
6156
6157 CONVERT_CHECKED(String, s, args[0]);
6158 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6159 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6160
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006161 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006162 int length = s->length();
6163
6164 int left = 0;
6165 if (trimLeft) {
6166 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6167 left++;
6168 }
6169 }
6170
6171 int right = length;
6172 if (trimRight) {
6173 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6174 right--;
6175 }
6176 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006177 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006178}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006179
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006181RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006182 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006183 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006184 CONVERT_ARG_CHECKED(String, subject, 0);
6185 CONVERT_ARG_CHECKED(String, pattern, 1);
6186 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6187
6188 int subject_length = subject->length();
6189 int pattern_length = pattern->length();
6190 RUNTIME_ASSERT(pattern_length > 0);
6191
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006192 if (limit == 0xffffffffu) {
6193 Handle<Object> cached_answer(StringSplitCache::Lookup(
6194 isolate->heap()->string_split_cache(),
6195 *subject,
6196 *pattern));
6197 if (*cached_answer != Smi::FromInt(0)) {
6198 Handle<JSArray> result =
6199 isolate->factory()->NewJSArrayWithElements(
6200 Handle<FixedArray>::cast(cached_answer));
6201 return *result;
6202 }
6203 }
6204
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006205 // The limit can be very large (0xffffffffu), but since the pattern
6206 // isn't empty, we can never create more parts than ~half the length
6207 // of the subject.
6208
6209 if (!subject->IsFlat()) FlattenString(subject);
6210
6211 static const int kMaxInitialListCapacity = 16;
6212
danno@chromium.org40cb8782011-05-25 07:58:50 +00006213 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006214
6215 // Find (up to limit) indices of separator and end-of-string in subject
6216 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6217 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006218 if (!pattern->IsFlat()) FlattenString(pattern);
6219
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006220 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006221
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006222 if (static_cast<uint32_t>(indices.length()) < limit) {
6223 indices.Add(subject_length);
6224 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006225
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006226 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006227
6228 // Create JSArray of substrings separated by separator.
6229 int part_count = indices.length();
6230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006231 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006232 result->set_length(Smi::FromInt(part_count));
6233
6234 ASSERT(result->HasFastElements());
6235
6236 if (part_count == 1 && indices.at(0) == subject_length) {
6237 FixedArray::cast(result->elements())->set(0, *subject);
6238 return *result;
6239 }
6240
6241 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6242 int part_start = 0;
6243 for (int i = 0; i < part_count; i++) {
6244 HandleScope local_loop_handle;
6245 int part_end = indices.at(i);
6246 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006247 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006248 elements->set(i, *substring);
6249 part_start = part_end + pattern_length;
6250 }
6251
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006252 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006253 if (result->HasFastElements()) {
6254 StringSplitCache::Enter(isolate->heap(),
6255 isolate->heap()->string_split_cache(),
6256 *subject,
6257 *pattern,
6258 *elements);
6259 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006260 }
6261
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006262 return *result;
6263}
6264
6265
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006266// Copies ascii characters to the given fixed array looking up
6267// one-char strings in the cache. Gives up on the first char that is
6268// not in the cache and fills the remainder with smi zeros. Returns
6269// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006270static int CopyCachedAsciiCharsToArray(Heap* heap,
6271 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006272 FixedArray* elements,
6273 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006274 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006275 FixedArray* ascii_cache = heap->single_character_string_cache();
6276 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006277 int i;
6278 for (i = 0; i < length; ++i) {
6279 Object* value = ascii_cache->get(chars[i]);
6280 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006281 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006282 elements->set(i, value, SKIP_WRITE_BARRIER);
6283 }
6284 if (i < length) {
6285 ASSERT(Smi::FromInt(0) == 0);
6286 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6287 }
6288#ifdef DEBUG
6289 for (int j = 0; j < length; ++j) {
6290 Object* element = elements->get(j);
6291 ASSERT(element == Smi::FromInt(0) ||
6292 (element->IsString() && String::cast(element)->LooksValid()));
6293 }
6294#endif
6295 return i;
6296}
6297
6298
6299// Converts a String to JSArray.
6300// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006301RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006302 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006303 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006304 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006305 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006306
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006307 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006308 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006309
6310 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006311 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006312 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006313 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006314 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006315 { MaybeObject* maybe_obj =
6316 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006317 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6318 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006319 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006320 String::FlatContent content = s->GetFlatContent();
6321 if (content.IsAscii()) {
6322 Vector<const char> chars = content.ToAsciiVector();
6323 // Note, this will initialize all elements (not only the prefix)
6324 // to prevent GC from seeing partially initialized array.
6325 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6326 chars.start(),
6327 *elements,
6328 length);
6329 } else {
6330 MemsetPointer(elements->data_start(),
6331 isolate->heap()->undefined_value(),
6332 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006333 }
6334 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006336 }
6337 for (int i = position; i < length; ++i) {
6338 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6339 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006340 }
6341
6342#ifdef DEBUG
6343 for (int i = 0; i < length; ++i) {
6344 ASSERT(String::cast(elements->get(i))->length() == 1);
6345 }
6346#endif
6347
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006348 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006349}
6350
6351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006352RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006353 NoHandleAllocation ha;
6354 ASSERT(args.length() == 1);
6355 CONVERT_CHECKED(String, value, args[0]);
6356 return value->ToObject();
6357}
6358
6359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006360bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006361 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006362 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006363 return char_length == 0;
6364}
6365
6366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006367RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006368 NoHandleAllocation ha;
6369 ASSERT(args.length() == 1);
6370
6371 Object* number = args[0];
6372 RUNTIME_ASSERT(number->IsNumber());
6373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006374 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006375}
6376
6377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006378RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006379 NoHandleAllocation ha;
6380 ASSERT(args.length() == 1);
6381
6382 Object* number = args[0];
6383 RUNTIME_ASSERT(number->IsNumber());
6384
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006385 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006386}
6387
6388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006389RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006390 NoHandleAllocation ha;
6391 ASSERT(args.length() == 1);
6392
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006393 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006394
6395 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6396 if (number > 0 && number <= Smi::kMaxValue) {
6397 return Smi::FromInt(static_cast<int>(number));
6398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006399 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006400}
6401
6402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006403RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006404 NoHandleAllocation ha;
6405 ASSERT(args.length() == 1);
6406
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006407 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006408
6409 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6410 if (number > 0 && number <= Smi::kMaxValue) {
6411 return Smi::FromInt(static_cast<int>(number));
6412 }
6413
6414 double double_value = DoubleToInteger(number);
6415 // Map both -0 and +0 to +0.
6416 if (double_value == 0) double_value = 0;
6417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006418 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006419}
6420
6421
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006422RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006423 NoHandleAllocation ha;
6424 ASSERT(args.length() == 1);
6425
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006426 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006427 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006428}
6429
6430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006431RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006432 NoHandleAllocation ha;
6433 ASSERT(args.length() == 1);
6434
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006435 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006436
6437 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6438 if (number > 0 && number <= Smi::kMaxValue) {
6439 return Smi::FromInt(static_cast<int>(number));
6440 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006441 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006442}
6443
6444
ager@chromium.org870a0b62008-11-04 11:43:05 +00006445// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6446// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006447RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006448 NoHandleAllocation ha;
6449 ASSERT(args.length() == 1);
6450
6451 Object* obj = args[0];
6452 if (obj->IsSmi()) {
6453 return obj;
6454 }
6455 if (obj->IsHeapNumber()) {
6456 double value = HeapNumber::cast(obj)->value();
6457 int int_value = FastD2I(value);
6458 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6459 return Smi::FromInt(int_value);
6460 }
6461 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006462 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006463}
6464
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006466RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006467 NoHandleAllocation ha;
6468 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006469 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006470}
6471
6472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006473RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006474 NoHandleAllocation ha;
6475 ASSERT(args.length() == 2);
6476
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006477 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6478 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006479 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006480}
6481
6482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006483RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006484 NoHandleAllocation ha;
6485 ASSERT(args.length() == 2);
6486
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006487 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6488 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006489 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006490}
6491
6492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006493RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006494 NoHandleAllocation ha;
6495 ASSERT(args.length() == 2);
6496
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006497 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6498 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500}
6501
6502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006503RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006504 NoHandleAllocation ha;
6505 ASSERT(args.length() == 1);
6506
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006507 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006508 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006509}
6510
6511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006512RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006513 NoHandleAllocation ha;
6514 ASSERT(args.length() == 0);
6515
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006516 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006517}
6518
6519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006521 NoHandleAllocation ha;
6522 ASSERT(args.length() == 2);
6523
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006524 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6525 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006526 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006527}
6528
6529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006530RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006531 NoHandleAllocation ha;
6532 ASSERT(args.length() == 2);
6533
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006534 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6535 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006536
ager@chromium.org3811b432009-10-28 14:53:37 +00006537 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006538 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006539 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006540}
6541
6542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006543RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006544 NoHandleAllocation ha;
6545 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006546 CONVERT_CHECKED(String, str1, args[0]);
6547 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006548 isolate->counters()->string_add_runtime()->Increment();
6549 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550}
6551
6552
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006553template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006554static inline void StringBuilderConcatHelper(String* special,
6555 sinkchar* sink,
6556 FixedArray* fixed_array,
6557 int array_length) {
6558 int position = 0;
6559 for (int i = 0; i < array_length; i++) {
6560 Object* element = fixed_array->get(i);
6561 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006562 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006563 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006564 int pos;
6565 int len;
6566 if (encoded_slice > 0) {
6567 // Position and length encoded in one smi.
6568 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6569 len = StringBuilderSubstringLength::decode(encoded_slice);
6570 } else {
6571 // Position and length encoded in two smis.
6572 Object* obj = fixed_array->get(++i);
6573 ASSERT(obj->IsSmi());
6574 pos = Smi::cast(obj)->value();
6575 len = -encoded_slice;
6576 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006577 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006578 sink + position,
6579 pos,
6580 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006581 position += len;
6582 } else {
6583 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006584 int element_length = string->length();
6585 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006586 position += element_length;
6587 }
6588 }
6589}
6590
6591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006592RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006594 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006595 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006596 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006597 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006598 return Failure::OutOfMemoryException();
6599 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006600 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006601 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006602
6603 // This assumption is used by the slice encoding in one or two smis.
6604 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6605
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006606 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006607 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006608 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609 }
6610 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006611 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006613 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006614
6615 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006616 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 } else if (array_length == 1) {
6618 Object* first = fixed_array->get(0);
6619 if (first->IsString()) return first;
6620 }
6621
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006622 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623 int position = 0;
6624 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006625 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006626 Object* elt = fixed_array->get(i);
6627 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006628 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006629 int smi_value = Smi::cast(elt)->value();
6630 int pos;
6631 int len;
6632 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006633 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006634 pos = StringBuilderSubstringPosition::decode(smi_value);
6635 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006636 } else {
6637 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006638 len = -smi_value;
6639 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006640 i++;
6641 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006642 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006643 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006644 Object* next_smi = fixed_array->get(i);
6645 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006646 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006647 }
6648 pos = Smi::cast(next_smi)->value();
6649 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006650 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006651 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006653 ASSERT(pos >= 0);
6654 ASSERT(len >= 0);
6655 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006656 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006657 }
6658 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006659 } else if (elt->IsString()) {
6660 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006661 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006662 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006663 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006664 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006665 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006667 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006668 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006669 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006670 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006671 return Failure::OutOfMemoryException();
6672 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006673 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006674 }
6675
6676 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006678
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006680 { MaybeObject* maybe_object =
6681 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006682 if (!maybe_object->ToObject(&object)) return maybe_object;
6683 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006684 SeqAsciiString* answer = SeqAsciiString::cast(object);
6685 StringBuilderConcatHelper(special,
6686 answer->GetChars(),
6687 fixed_array,
6688 array_length);
6689 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006690 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006691 { MaybeObject* maybe_object =
6692 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006693 if (!maybe_object->ToObject(&object)) return maybe_object;
6694 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006695 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6696 StringBuilderConcatHelper(special,
6697 answer->GetChars(),
6698 fixed_array,
6699 array_length);
6700 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702}
6703
6704
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006705RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006706 NoHandleAllocation ha;
6707 ASSERT(args.length() == 3);
6708 CONVERT_CHECKED(JSArray, array, args[0]);
6709 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006710 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006711 return Failure::OutOfMemoryException();
6712 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006713 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006714 CONVERT_CHECKED(String, separator, args[2]);
6715
6716 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006717 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006718 }
6719 FixedArray* fixed_array = FixedArray::cast(array->elements());
6720 if (fixed_array->length() < array_length) {
6721 array_length = fixed_array->length();
6722 }
6723
6724 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006725 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006726 } else if (array_length == 1) {
6727 Object* first = fixed_array->get(0);
6728 if (first->IsString()) return first;
6729 }
6730
6731 int separator_length = separator->length();
6732 int max_nof_separators =
6733 (String::kMaxLength + separator_length - 1) / separator_length;
6734 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006735 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006736 return Failure::OutOfMemoryException();
6737 }
6738 int length = (array_length - 1) * separator_length;
6739 for (int i = 0; i < array_length; i++) {
6740 Object* element_obj = fixed_array->get(i);
6741 if (!element_obj->IsString()) {
6742 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006743 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006744 }
6745 String* element = String::cast(element_obj);
6746 int increment = element->length();
6747 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006748 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006749 return Failure::OutOfMemoryException();
6750 }
6751 length += increment;
6752 }
6753
6754 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006755 { MaybeObject* maybe_object =
6756 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006757 if (!maybe_object->ToObject(&object)) return maybe_object;
6758 }
6759 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6760
6761 uc16* sink = answer->GetChars();
6762#ifdef DEBUG
6763 uc16* end = sink + length;
6764#endif
6765
6766 String* first = String::cast(fixed_array->get(0));
6767 int first_length = first->length();
6768 String::WriteToFlat(first, sink, 0, first_length);
6769 sink += first_length;
6770
6771 for (int i = 1; i < array_length; i++) {
6772 ASSERT(sink + separator_length <= end);
6773 String::WriteToFlat(separator, sink, 0, separator_length);
6774 sink += separator_length;
6775
6776 String* element = String::cast(fixed_array->get(i));
6777 int element_length = element->length();
6778 ASSERT(sink + element_length <= end);
6779 String::WriteToFlat(element, sink, 0, element_length);
6780 sink += element_length;
6781 }
6782 ASSERT(sink == end);
6783
6784 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6785 return answer;
6786}
6787
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006788template <typename Char>
6789static void JoinSparseArrayWithSeparator(FixedArray* elements,
6790 int elements_length,
6791 uint32_t array_length,
6792 String* separator,
6793 Vector<Char> buffer) {
6794 int previous_separator_position = 0;
6795 int separator_length = separator->length();
6796 int cursor = 0;
6797 for (int i = 0; i < elements_length; i += 2) {
6798 int position = NumberToInt32(elements->get(i));
6799 String* string = String::cast(elements->get(i + 1));
6800 int string_length = string->length();
6801 if (string->length() > 0) {
6802 while (previous_separator_position < position) {
6803 String::WriteToFlat<Char>(separator, &buffer[cursor],
6804 0, separator_length);
6805 cursor += separator_length;
6806 previous_separator_position++;
6807 }
6808 String::WriteToFlat<Char>(string, &buffer[cursor],
6809 0, string_length);
6810 cursor += string->length();
6811 }
6812 }
6813 if (separator_length > 0) {
6814 // Array length must be representable as a signed 32-bit number,
6815 // otherwise the total string length would have been too large.
6816 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6817 int last_array_index = static_cast<int>(array_length - 1);
6818 while (previous_separator_position < last_array_index) {
6819 String::WriteToFlat<Char>(separator, &buffer[cursor],
6820 0, separator_length);
6821 cursor += separator_length;
6822 previous_separator_position++;
6823 }
6824 }
6825 ASSERT(cursor <= buffer.length());
6826}
6827
6828
6829RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6830 NoHandleAllocation ha;
6831 ASSERT(args.length() == 3);
6832 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6833 RUNTIME_ASSERT(elements_array->HasFastElements());
6834 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6835 CONVERT_CHECKED(String, separator, args[2]);
6836 // elements_array is fast-mode JSarray of alternating positions
6837 // (increasing order) and strings.
6838 // array_length is length of original array (used to add separators);
6839 // separator is string to put between elements. Assumed to be non-empty.
6840
6841 // Find total length of join result.
6842 int string_length = 0;
6843 bool is_ascii = true;
6844 int max_string_length = SeqAsciiString::kMaxLength;
6845 bool overflow = false;
6846 CONVERT_NUMBER_CHECKED(int, elements_length,
6847 Int32, elements_array->length());
6848 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6849 FixedArray* elements = FixedArray::cast(elements_array->elements());
6850 for (int i = 0; i < elements_length; i += 2) {
6851 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6852 CONVERT_CHECKED(String, string, elements->get(i + 1));
6853 int length = string->length();
6854 if (is_ascii && !string->IsAsciiRepresentation()) {
6855 is_ascii = false;
6856 max_string_length = SeqTwoByteString::kMaxLength;
6857 }
6858 if (length > max_string_length ||
6859 max_string_length - length < string_length) {
6860 overflow = true;
6861 break;
6862 }
6863 string_length += length;
6864 }
6865 int separator_length = separator->length();
6866 if (!overflow && separator_length > 0) {
6867 if (array_length <= 0x7fffffffu) {
6868 int separator_count = static_cast<int>(array_length) - 1;
6869 int remaining_length = max_string_length - string_length;
6870 if ((remaining_length / separator_length) >= separator_count) {
6871 string_length += separator_length * (array_length - 1);
6872 } else {
6873 // Not room for the separators within the maximal string length.
6874 overflow = true;
6875 }
6876 } else {
6877 // Nonempty separator and at least 2^31-1 separators necessary
6878 // means that the string is too large to create.
6879 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6880 overflow = true;
6881 }
6882 }
6883 if (overflow) {
6884 // Throw OutOfMemory exception for creating too large a string.
6885 V8::FatalProcessOutOfMemory("Array join result too large.");
6886 }
6887
6888 if (is_ascii) {
6889 MaybeObject* result_allocation =
6890 isolate->heap()->AllocateRawAsciiString(string_length);
6891 if (result_allocation->IsFailure()) return result_allocation;
6892 SeqAsciiString* result_string =
6893 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6894 JoinSparseArrayWithSeparator<char>(elements,
6895 elements_length,
6896 array_length,
6897 separator,
6898 Vector<char>(result_string->GetChars(),
6899 string_length));
6900 return result_string;
6901 } else {
6902 MaybeObject* result_allocation =
6903 isolate->heap()->AllocateRawTwoByteString(string_length);
6904 if (result_allocation->IsFailure()) return result_allocation;
6905 SeqTwoByteString* result_string =
6906 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6907 JoinSparseArrayWithSeparator<uc16>(elements,
6908 elements_length,
6909 array_length,
6910 separator,
6911 Vector<uc16>(result_string->GetChars(),
6912 string_length));
6913 return result_string;
6914 }
6915}
6916
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006918RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006919 NoHandleAllocation ha;
6920 ASSERT(args.length() == 2);
6921
6922 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6923 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006924 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006925}
6926
6927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006928RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006929 NoHandleAllocation ha;
6930 ASSERT(args.length() == 2);
6931
6932 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6933 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006934 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006935}
6936
6937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006938RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006939 NoHandleAllocation ha;
6940 ASSERT(args.length() == 2);
6941
6942 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6943 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006944 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006945}
6946
6947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006948RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006949 NoHandleAllocation ha;
6950 ASSERT(args.length() == 1);
6951
6952 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006953 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006954}
6955
6956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006957RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006958 NoHandleAllocation ha;
6959 ASSERT(args.length() == 2);
6960
6961 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6962 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006963 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006964}
6965
6966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006967RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006968 NoHandleAllocation ha;
6969 ASSERT(args.length() == 2);
6970
6971 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6972 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006973 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006974}
6975
6976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006977RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006978 NoHandleAllocation ha;
6979 ASSERT(args.length() == 2);
6980
6981 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6982 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006983 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006984}
6985
6986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006987RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006988 NoHandleAllocation ha;
6989 ASSERT(args.length() == 2);
6990
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006991 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6992 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006993 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6994 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6995 if (x == y) return Smi::FromInt(EQUAL);
6996 Object* result;
6997 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6998 result = Smi::FromInt(EQUAL);
6999 } else {
7000 result = Smi::FromInt(NOT_EQUAL);
7001 }
7002 return result;
7003}
7004
7005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007006RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007 NoHandleAllocation ha;
7008 ASSERT(args.length() == 2);
7009
7010 CONVERT_CHECKED(String, x, args[0]);
7011 CONVERT_CHECKED(String, y, args[1]);
7012
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007013 bool not_equal = !x->Equals(y);
7014 // This is slightly convoluted because the value that signifies
7015 // equality is 0 and inequality is 1 so we have to negate the result
7016 // from String::Equals.
7017 ASSERT(not_equal == 0 || not_equal == 1);
7018 STATIC_CHECK(EQUAL == 0);
7019 STATIC_CHECK(NOT_EQUAL == 1);
7020 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007021}
7022
7023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007024RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025 NoHandleAllocation ha;
7026 ASSERT(args.length() == 3);
7027
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007028 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7029 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007030 if (isnan(x) || isnan(y)) return args[2];
7031 if (x == y) return Smi::FromInt(EQUAL);
7032 if (isless(x, y)) return Smi::FromInt(LESS);
7033 return Smi::FromInt(GREATER);
7034}
7035
7036
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007037// Compare two Smis as if they were converted to strings and then
7038// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007039RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007040 NoHandleAllocation ha;
7041 ASSERT(args.length() == 2);
7042
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007043 // Extract the integer values from the Smis.
7044 CONVERT_CHECKED(Smi, x, args[0]);
7045 CONVERT_CHECKED(Smi, y, args[1]);
7046 int x_value = x->value();
7047 int y_value = y->value();
7048
7049 // If the integers are equal so are the string representations.
7050 if (x_value == y_value) return Smi::FromInt(EQUAL);
7051
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007052 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007053 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007054 if (x_value == 0 || y_value == 0)
7055 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007056
ager@chromium.org32912102009-01-16 10:38:43 +00007057 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007058 // smallest because the char code of '-' is less than the char code
7059 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007060
7061 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7062 // architectures using 32-bit Smis.
7063 uint32_t x_scaled = x_value;
7064 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007065 if (x_value < 0 || y_value < 0) {
7066 if (y_value >= 0) return Smi::FromInt(LESS);
7067 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007068 x_scaled = -x_value;
7069 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007070 }
7071
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007072 static const uint32_t kPowersOf10[] = {
7073 1, 10, 100, 1000, 10*1000, 100*1000,
7074 1000*1000, 10*1000*1000, 100*1000*1000,
7075 1000*1000*1000
7076 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007077
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007078 // If the integers have the same number of decimal digits they can be
7079 // compared directly as the numeric order is the same as the
7080 // lexicographic order. If one integer has fewer digits, it is scaled
7081 // by some power of 10 to have the same number of digits as the longer
7082 // integer. If the scaled integers are equal it means the shorter
7083 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007084
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007085 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7086 int x_log2 = IntegerLog2(x_scaled);
7087 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7088 x_log10 -= x_scaled < kPowersOf10[x_log10];
7089
7090 int y_log2 = IntegerLog2(y_scaled);
7091 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7092 y_log10 -= y_scaled < kPowersOf10[y_log10];
7093
7094 int tie = EQUAL;
7095
7096 if (x_log10 < y_log10) {
7097 // X has fewer digits. We would like to simply scale up X but that
7098 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7099 // be scaled up to 9_000_000_000. So we scale up by the next
7100 // smallest power and scale down Y to drop one digit. It is OK to
7101 // drop one digit from the longer integer since the final digit is
7102 // past the length of the shorter integer.
7103 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7104 y_scaled /= 10;
7105 tie = LESS;
7106 } else if (y_log10 < x_log10) {
7107 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7108 x_scaled /= 10;
7109 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007110 }
7111
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007112 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7113 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7114 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007115}
7116
7117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007118static Object* StringInputBufferCompare(RuntimeState* state,
7119 String* x,
7120 String* y) {
7121 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7122 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007123 bufx.Reset(x);
7124 bufy.Reset(y);
7125 while (bufx.has_more() && bufy.has_more()) {
7126 int d = bufx.GetNext() - bufy.GetNext();
7127 if (d < 0) return Smi::FromInt(LESS);
7128 else if (d > 0) return Smi::FromInt(GREATER);
7129 }
7130
7131 // x is (non-trivial) prefix of y:
7132 if (bufy.has_more()) return Smi::FromInt(LESS);
7133 // y is prefix of x:
7134 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7135}
7136
7137
7138static Object* FlatStringCompare(String* x, String* y) {
7139 ASSERT(x->IsFlat());
7140 ASSERT(y->IsFlat());
7141 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7142 int prefix_length = x->length();
7143 if (y->length() < prefix_length) {
7144 prefix_length = y->length();
7145 equal_prefix_result = Smi::FromInt(GREATER);
7146 } else if (y->length() > prefix_length) {
7147 equal_prefix_result = Smi::FromInt(LESS);
7148 }
7149 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007150 String::FlatContent x_content = x->GetFlatContent();
7151 String::FlatContent y_content = y->GetFlatContent();
7152 if (x_content.IsAscii()) {
7153 Vector<const char> x_chars = x_content.ToAsciiVector();
7154 if (y_content.IsAscii()) {
7155 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007156 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007157 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007158 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007159 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7160 }
7161 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007162 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7163 if (y_content.IsAscii()) {
7164 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007165 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7166 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007167 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007168 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7169 }
7170 }
7171 Object* result;
7172 if (r == 0) {
7173 result = equal_prefix_result;
7174 } else {
7175 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7176 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007177 ASSERT(result ==
7178 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007179 return result;
7180}
7181
7182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007183RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007184 NoHandleAllocation ha;
7185 ASSERT(args.length() == 2);
7186
7187 CONVERT_CHECKED(String, x, args[0]);
7188 CONVERT_CHECKED(String, y, args[1]);
7189
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007190 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007191
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007192 // A few fast case tests before we flatten.
7193 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007194 if (y->length() == 0) {
7195 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007196 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007197 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007198 return Smi::FromInt(LESS);
7199 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007200
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007201 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007202 if (d < 0) return Smi::FromInt(LESS);
7203 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007204
lrn@chromium.org303ada72010-10-27 09:33:13 +00007205 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007206 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007207 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7208 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007209 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007210 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007212
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007213 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007214 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007215}
7216
7217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007218RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007219 NoHandleAllocation ha;
7220 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007221 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007222
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007223 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007224 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007225}
7226
7227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007228RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007229 NoHandleAllocation ha;
7230 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007231 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007232
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007233 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007234 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007235}
7236
7237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007238RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007239 NoHandleAllocation ha;
7240 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007241 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007242
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007243 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007244 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007245}
7246
7247
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007248static const double kPiDividedBy4 = 0.78539816339744830962;
7249
7250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007251RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007252 NoHandleAllocation ha;
7253 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007254 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007255
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007256 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7257 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007258 double result;
7259 if (isinf(x) && isinf(y)) {
7260 // Make sure that the result in case of two infinite arguments
7261 // is a multiple of Pi / 4. The sign of the result is determined
7262 // by the first argument (x) and the sign of the second argument
7263 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007264 int multiplier = (x < 0) ? -1 : 1;
7265 if (y < 0) multiplier *= 3;
7266 result = multiplier * kPiDividedBy4;
7267 } else {
7268 result = atan2(x, y);
7269 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007270 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007271}
7272
7273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007274RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007275 NoHandleAllocation ha;
7276 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007277 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007278
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007279 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007280 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007281}
7282
7283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007284RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007285 NoHandleAllocation ha;
7286 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007287 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007289 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007290 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007291}
7292
7293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007294RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007295 NoHandleAllocation ha;
7296 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007297 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007298
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007299 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007300 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301}
7302
7303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007304RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007305 NoHandleAllocation ha;
7306 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007307 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007308
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007309 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007310 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311}
7312
7313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007314RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007315 NoHandleAllocation ha;
7316 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007317 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007319 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321}
7322
7323
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007324RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007325 NoHandleAllocation ha;
7326 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007327 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007328
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007329 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007330
7331 // If the second argument is a smi, it is much faster to call the
7332 // custom powi() function than the generic pow().
7333 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007334 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007335 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007336 }
7337
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007338 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007339 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007340}
7341
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007342// Fast version of Math.pow if we know that y is not an integer and
7343// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007344RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007345 NoHandleAllocation ha;
7346 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007347 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7348 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007349 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007350 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007351 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007352 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007353 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007354 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007355 }
7356}
7357
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007359RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360 NoHandleAllocation ha;
7361 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007362 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007364 if (!args[0]->IsHeapNumber()) {
7365 // Must be smi. Return the argument unchanged for all the other types
7366 // to make fuzz-natives test happy.
7367 return args[0];
7368 }
7369
7370 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7371
7372 double value = number->value();
7373 int exponent = number->get_exponent();
7374 int sign = number->get_sign();
7375
danno@chromium.org160a7b02011-04-18 15:51:38 +00007376 if (exponent < -1) {
7377 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7378 if (sign) return isolate->heap()->minus_zero_value();
7379 return Smi::FromInt(0);
7380 }
7381
7382 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7383 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7384 // agument holds for 32-bit smis).
7385 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007386 return Smi::FromInt(static_cast<int>(value + 0.5));
7387 }
7388
7389 // If the magnitude is big enough, there's no place for fraction part. If we
7390 // try to add 0.5 to this number, 1.0 will be added instead.
7391 if (exponent >= 52) {
7392 return number;
7393 }
7394
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007395 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007396
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007397 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007398 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007399}
7400
7401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007402RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403 NoHandleAllocation ha;
7404 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007405 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007406
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007407 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007408 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007409}
7410
7411
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007412RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413 NoHandleAllocation ha;
7414 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007415 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007416
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007417 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007418 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007419}
7420
7421
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007422RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007423 NoHandleAllocation ha;
7424 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007425 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007426
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007427 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007428 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007429}
7430
7431
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007432static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007433 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7434 181, 212, 243, 273, 304, 334};
7435 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7436 182, 213, 244, 274, 305, 335};
7437
7438 year += month / 12;
7439 month %= 12;
7440 if (month < 0) {
7441 year--;
7442 month += 12;
7443 }
7444
7445 ASSERT(month >= 0);
7446 ASSERT(month < 12);
7447
7448 // year_delta is an arbitrary number such that:
7449 // a) year_delta = -1 (mod 400)
7450 // b) year + year_delta > 0 for years in the range defined by
7451 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7452 // Jan 1 1970. This is required so that we don't run into integer
7453 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007454 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007455 // operations.
7456 static const int year_delta = 399999;
7457 static const int base_day = 365 * (1970 + year_delta) +
7458 (1970 + year_delta) / 4 -
7459 (1970 + year_delta) / 100 +
7460 (1970 + year_delta) / 400;
7461
7462 int year1 = year + year_delta;
7463 int day_from_year = 365 * year1 +
7464 year1 / 4 -
7465 year1 / 100 +
7466 year1 / 400 -
7467 base_day;
7468
7469 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007470 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007471 }
7472
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007473 return day_from_year + day_from_month_leap[month] + day - 1;
7474}
7475
7476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007477RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007478 NoHandleAllocation ha;
7479 ASSERT(args.length() == 3);
7480
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007481 CONVERT_SMI_ARG_CHECKED(year, 0);
7482 CONVERT_SMI_ARG_CHECKED(month, 1);
7483 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007484
7485 return Smi::FromInt(MakeDay(year, month, date));
7486}
7487
7488
7489static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7490static const int kDaysIn4Years = 4 * 365 + 1;
7491static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7492static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7493static const int kDays1970to2000 = 30 * 365 + 7;
7494static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7495 kDays1970to2000;
7496static const int kYearsOffset = 400000;
7497
7498static const char kDayInYear[] = {
7499 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7500 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7501 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7502 22, 23, 24, 25, 26, 27, 28,
7503 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7504 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7505 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7506 22, 23, 24, 25, 26, 27, 28, 29, 30,
7507 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7508 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7509 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7510 22, 23, 24, 25, 26, 27, 28, 29, 30,
7511 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7512 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7513 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7514 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7515 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7516 22, 23, 24, 25, 26, 27, 28, 29, 30,
7517 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7518 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7519 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7520 22, 23, 24, 25, 26, 27, 28, 29, 30,
7521 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7522 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7523
7524 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7525 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7526 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7527 22, 23, 24, 25, 26, 27, 28,
7528 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7529 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7530 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7531 22, 23, 24, 25, 26, 27, 28, 29, 30,
7532 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7533 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7534 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7535 22, 23, 24, 25, 26, 27, 28, 29, 30,
7536 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7537 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7538 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7539 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7540 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7541 22, 23, 24, 25, 26, 27, 28, 29, 30,
7542 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7543 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7544 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7545 22, 23, 24, 25, 26, 27, 28, 29, 30,
7546 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7547 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7548
7549 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7550 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7551 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7552 22, 23, 24, 25, 26, 27, 28, 29,
7553 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7554 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7555 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7556 22, 23, 24, 25, 26, 27, 28, 29, 30,
7557 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7558 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7559 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7560 22, 23, 24, 25, 26, 27, 28, 29, 30,
7561 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7562 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7563 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7564 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7565 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7566 22, 23, 24, 25, 26, 27, 28, 29, 30,
7567 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7568 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7569 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7570 22, 23, 24, 25, 26, 27, 28, 29, 30,
7571 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7572 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7573
7574 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7575 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7576 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7577 22, 23, 24, 25, 26, 27, 28,
7578 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7579 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7580 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7581 22, 23, 24, 25, 26, 27, 28, 29, 30,
7582 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7583 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7584 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7585 22, 23, 24, 25, 26, 27, 28, 29, 30,
7586 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7587 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7588 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7589 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7590 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7591 22, 23, 24, 25, 26, 27, 28, 29, 30,
7592 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7593 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7594 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7595 22, 23, 24, 25, 26, 27, 28, 29, 30,
7596 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7597 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7598
7599static const char kMonthInYear[] = {
7600 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7601 0, 0, 0, 0, 0, 0,
7602 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7603 1, 1, 1,
7604 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7605 2, 2, 2, 2, 2, 2,
7606 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7607 3, 3, 3, 3, 3,
7608 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7609 4, 4, 4, 4, 4, 4,
7610 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7611 5, 5, 5, 5, 5,
7612 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7613 6, 6, 6, 6, 6, 6,
7614 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7615 7, 7, 7, 7, 7, 7,
7616 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7617 8, 8, 8, 8, 8,
7618 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7619 9, 9, 9, 9, 9, 9,
7620 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7621 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7622 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7623 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7624
7625 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7626 0, 0, 0, 0, 0, 0,
7627 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7628 1, 1, 1,
7629 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7630 2, 2, 2, 2, 2, 2,
7631 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7632 3, 3, 3, 3, 3,
7633 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7634 4, 4, 4, 4, 4, 4,
7635 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7636 5, 5, 5, 5, 5,
7637 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7638 6, 6, 6, 6, 6, 6,
7639 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7640 7, 7, 7, 7, 7, 7,
7641 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7642 8, 8, 8, 8, 8,
7643 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7644 9, 9, 9, 9, 9, 9,
7645 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7646 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7647 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7648 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7649
7650 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7651 0, 0, 0, 0, 0, 0,
7652 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7653 1, 1, 1, 1,
7654 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7655 2, 2, 2, 2, 2, 2,
7656 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7657 3, 3, 3, 3, 3,
7658 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7659 4, 4, 4, 4, 4, 4,
7660 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7661 5, 5, 5, 5, 5,
7662 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7663 6, 6, 6, 6, 6, 6,
7664 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7665 7, 7, 7, 7, 7, 7,
7666 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7667 8, 8, 8, 8, 8,
7668 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7669 9, 9, 9, 9, 9, 9,
7670 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7671 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7672 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7673 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7674
7675 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7676 0, 0, 0, 0, 0, 0,
7677 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7678 1, 1, 1,
7679 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7680 2, 2, 2, 2, 2, 2,
7681 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7682 3, 3, 3, 3, 3,
7683 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7684 4, 4, 4, 4, 4, 4,
7685 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7686 5, 5, 5, 5, 5,
7687 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7688 6, 6, 6, 6, 6, 6,
7689 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7690 7, 7, 7, 7, 7, 7,
7691 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7692 8, 8, 8, 8, 8,
7693 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7694 9, 9, 9, 9, 9, 9,
7695 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7696 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7697 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7698 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7699
7700
7701// This function works for dates from 1970 to 2099.
7702static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007703 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007704#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007705 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007706#endif
7707
7708 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7709 date %= kDaysIn4Years;
7710
7711 month = kMonthInYear[date];
7712 day = kDayInYear[date];
7713
7714 ASSERT(MakeDay(year, month, day) == save_date);
7715}
7716
7717
7718static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007719 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007720#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007721 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007722#endif
7723
7724 date += kDaysOffset;
7725 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7726 date %= kDaysIn400Years;
7727
7728 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7729
7730 date--;
7731 int yd1 = date / kDaysIn100Years;
7732 date %= kDaysIn100Years;
7733 year += 100 * yd1;
7734
7735 date++;
7736 int yd2 = date / kDaysIn4Years;
7737 date %= kDaysIn4Years;
7738 year += 4 * yd2;
7739
7740 date--;
7741 int yd3 = date / 365;
7742 date %= 365;
7743 year += yd3;
7744
7745 bool is_leap = (!yd1 || yd2) && !yd3;
7746
7747 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007748 ASSERT(is_leap || (date >= 0));
7749 ASSERT((date < 365) || (is_leap && (date < 366)));
7750 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7751 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7752 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007753
7754 if (is_leap) {
7755 day = kDayInYear[2*365 + 1 + date];
7756 month = kMonthInYear[2*365 + 1 + date];
7757 } else {
7758 day = kDayInYear[date];
7759 month = kMonthInYear[date];
7760 }
7761
7762 ASSERT(MakeDay(year, month, day) == save_date);
7763}
7764
7765
7766static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007767 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007768 if (date >= 0 && date < 32 * kDaysIn4Years) {
7769 DateYMDFromTimeAfter1970(date, year, month, day);
7770 } else {
7771 DateYMDFromTimeSlow(date, year, month, day);
7772 }
7773}
7774
7775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007776RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007777 NoHandleAllocation ha;
7778 ASSERT(args.length() == 2);
7779
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007780 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007781 CONVERT_CHECKED(JSArray, res_array, args[1]);
7782
7783 int year, month, day;
7784 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007786 RUNTIME_ASSERT(res_array->elements()->map() ==
7787 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007788 FixedArray* elms = FixedArray::cast(res_array->elements());
7789 RUNTIME_ASSERT(elms->length() == 3);
7790
7791 elms->set(0, Smi::FromInt(year));
7792 elms->set(1, Smi::FromInt(month));
7793 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007794
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007795 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007796}
7797
7798
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007799RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007800 HandleScope scope(isolate);
7801 ASSERT(args.length() == 3);
7802
7803 Handle<JSFunction> callee = args.at<JSFunction>(0);
7804 Object** parameters = reinterpret_cast<Object**>(args[1]);
7805 const int argument_count = Smi::cast(args[2])->value();
7806
7807 Handle<JSObject> result =
7808 isolate->factory()->NewArgumentsObject(callee, argument_count);
7809 // Allocate the elements if needed.
7810 int parameter_count = callee->shared()->formal_parameter_count();
7811 if (argument_count > 0) {
7812 if (parameter_count > 0) {
7813 int mapped_count = Min(argument_count, parameter_count);
7814 Handle<FixedArray> parameter_map =
7815 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7816 parameter_map->set_map(
7817 isolate->heap()->non_strict_arguments_elements_map());
7818
7819 Handle<Map> old_map(result->map());
7820 Handle<Map> new_map =
7821 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007822 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007823
7824 result->set_map(*new_map);
7825 result->set_elements(*parameter_map);
7826
7827 // Store the context and the arguments array at the beginning of the
7828 // parameter map.
7829 Handle<Context> context(isolate->context());
7830 Handle<FixedArray> arguments =
7831 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7832 parameter_map->set(0, *context);
7833 parameter_map->set(1, *arguments);
7834
7835 // Loop over the actual parameters backwards.
7836 int index = argument_count - 1;
7837 while (index >= mapped_count) {
7838 // These go directly in the arguments array and have no
7839 // corresponding slot in the parameter map.
7840 arguments->set(index, *(parameters - index - 1));
7841 --index;
7842 }
7843
7844 ScopeInfo<> scope_info(callee->shared()->scope_info());
7845 while (index >= 0) {
7846 // Detect duplicate names to the right in the parameter list.
7847 Handle<String> name = scope_info.parameter_name(index);
7848 int context_slot_count = scope_info.number_of_context_slots();
7849 bool duplicate = false;
7850 for (int j = index + 1; j < parameter_count; ++j) {
7851 if (scope_info.parameter_name(j).is_identical_to(name)) {
7852 duplicate = true;
7853 break;
7854 }
7855 }
7856
7857 if (duplicate) {
7858 // This goes directly in the arguments array with a hole in the
7859 // parameter map.
7860 arguments->set(index, *(parameters - index - 1));
7861 parameter_map->set_the_hole(index + 2);
7862 } else {
7863 // The context index goes in the parameter map with a hole in the
7864 // arguments array.
7865 int context_index = -1;
7866 for (int j = Context::MIN_CONTEXT_SLOTS;
7867 j < context_slot_count;
7868 ++j) {
7869 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7870 context_index = j;
7871 break;
7872 }
7873 }
7874 ASSERT(context_index >= 0);
7875 arguments->set_the_hole(index);
7876 parameter_map->set(index + 2, Smi::FromInt(context_index));
7877 }
7878
7879 --index;
7880 }
7881 } else {
7882 // If there is no aliasing, the arguments object elements are not
7883 // special in any way.
7884 Handle<FixedArray> elements =
7885 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7886 result->set_elements(*elements);
7887 for (int i = 0; i < argument_count; ++i) {
7888 elements->set(i, *(parameters - i - 1));
7889 }
7890 }
7891 }
7892 return *result;
7893}
7894
7895
7896RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007897 NoHandleAllocation ha;
7898 ASSERT(args.length() == 3);
7899
7900 JSFunction* callee = JSFunction::cast(args[0]);
7901 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007902 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007903
lrn@chromium.org303ada72010-10-27 09:33:13 +00007904 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007905 { MaybeObject* maybe_result =
7906 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007907 if (!maybe_result->ToObject(&result)) return maybe_result;
7908 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007909 // Allocate the elements if needed.
7910 if (length > 0) {
7911 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007912 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007913 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007914 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7915 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007916
7917 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007918 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007919 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007920 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007921
7922 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007923 for (int i = 0; i < length; i++) {
7924 array->set(i, *--parameters, mode);
7925 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007926 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007927 }
7928 return result;
7929}
7930
7931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007932RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007933 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007934 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007935 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007936 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007937 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007938
whesse@chromium.org7b260152011-06-20 15:33:18 +00007939 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007940 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007941 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007942 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007943 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7944 context,
7945 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007946 return *result;
7947}
7948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007949
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007950static SmartArrayPointer<Object**> GetNonBoundArguments(int bound_argc,
7951 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007952 // Find frame containing arguments passed to the caller.
7953 JavaScriptFrameIterator it;
7954 JavaScriptFrame* frame = it.frame();
7955 List<JSFunction*> functions(2);
7956 frame->GetFunctions(&functions);
7957 if (functions.length() > 1) {
7958 int inlined_frame_index = functions.length() - 1;
7959 JSFunction* inlined_function = functions[inlined_frame_index];
7960 int args_count = inlined_function->shared()->formal_parameter_count();
7961 ScopedVector<SlotRef> args_slots(args_count);
7962 SlotRef::ComputeSlotMappingForArguments(frame,
7963 inlined_frame_index,
7964 &args_slots);
7965
7966 *total_argc = bound_argc + args_count;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007967 SmartArrayPointer<Object**> param_data(NewArray<Object**>(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007968 for (int i = 0; i < args_count; i++) {
7969 Handle<Object> val = args_slots[i].GetValue();
7970 param_data[bound_argc + i] = val.location();
7971 }
7972 return param_data;
7973 } else {
7974 it.AdvanceToArgumentsFrame();
7975 frame = it.frame();
7976 int args_count = frame->ComputeParametersCount();
7977
7978 *total_argc = bound_argc + args_count;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007979 SmartArrayPointer<Object**> param_data(NewArray<Object**>(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007980 for (int i = 0; i < args_count; i++) {
7981 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7982 param_data[bound_argc + i] = val.location();
7983 }
7984 return param_data;
7985 }
7986}
7987
7988
7989RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007990 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007991 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007992 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007993 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007994
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007995 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007996 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007997 int bound_argc = 0;
7998 if (!args[1]->IsNull()) {
7999 CONVERT_ARG_CHECKED(JSArray, params, 1);
8000 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008001 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008002 bound_argc = Smi::cast(params->length())->value();
8003 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008005 int total_argc = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008006 SmartArrayPointer<Object**> param_data =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008007 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008008 for (int i = 0; i < bound_argc; i++) {
8009 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008010 param_data[i] = val.location();
8011 }
8012
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008013 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008014 Handle<Object> result =
8015 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008016 if (exception) {
8017 return Failure::Exception();
8018 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008019
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008020 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008021 return *result;
8022}
8023
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008025static void TrySettingInlineConstructStub(Isolate* isolate,
8026 Handle<JSFunction> function) {
8027 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008028 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008029 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008030 }
8031 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008032 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00008033 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008034 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008035 function->shared()->set_construct_stub(
8036 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008037 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008038 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008039}
8040
8041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008042RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008043 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008044 ASSERT(args.length() == 1);
8045
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008046 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008047
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008048 // If the constructor isn't a proper function we throw a type error.
8049 if (!constructor->IsJSFunction()) {
8050 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8051 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008052 isolate->factory()->NewTypeError("not_constructor", arguments);
8053 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008054 }
8055
8056 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008057
8058 // If function should not have prototype, construction is not allowed. In this
8059 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008060 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008061 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8062 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008063 isolate->factory()->NewTypeError("not_constructor", arguments);
8064 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008065 }
8066
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008067#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008068 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008069 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008070 if (debug->StepInActive()) {
8071 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008072 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008073#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008074
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008075 if (function->has_initial_map()) {
8076 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008077 // The 'Function' function ignores the receiver object when
8078 // called using 'new' and creates a new JSFunction object that
8079 // is returned. The receiver object is only used for error
8080 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008081 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008082 // allocate JSFunctions since it does not properly initialize
8083 // the shared part of the function. Since the receiver is
8084 // ignored anyway, we use the global object as the receiver
8085 // instead of a new JSFunction object. This way, errors are
8086 // reported the same way whether or not 'Function' is called
8087 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008088 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008089 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008090 }
8091
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008092 // The function should be compiled for the optimization hints to be
8093 // available. We cannot use EnsureCompiled because that forces a
8094 // compilation through the shared function info which makes it
8095 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008096 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008097 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008098
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008099 if (!function->has_initial_map() &&
8100 shared->IsInobjectSlackTrackingInProgress()) {
8101 // The tracking is already in progress for another function. We can only
8102 // track one initial_map at a time, so we force the completion before the
8103 // function is called as a constructor for the first time.
8104 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008105 }
8106
8107 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008108 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8109 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008110 // Delay setting the stub if inobject slack tracking is in progress.
8111 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008112 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008113 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008114
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008115 isolate->counters()->constructed_objects()->Increment();
8116 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008117
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008118 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008119}
8120
8121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008122RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008123 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008124 ASSERT(args.length() == 1);
8125
8126 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8127 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008128 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008129
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008130 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008131}
8132
8133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008134RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008135 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008136 ASSERT(args.length() == 1);
8137
8138 Handle<JSFunction> function = args.at<JSFunction>(0);
8139#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008140 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008141 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008142 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008143 PrintF("]\n");
8144 }
8145#endif
8146
lrn@chromium.org34e60782011-09-15 07:25:40 +00008147 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008148 ASSERT(!function->is_compiled());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008149 if (!CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008150 return Failure::Exception();
8151 }
8152
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008153 // All done. Return the compiled code.
8154 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008155 return function->code();
8156}
8157
8158
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008159RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008160 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008161 ASSERT(args.length() == 1);
8162 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008163
8164 // If the function is not compiled ignore the lazy
8165 // recompilation. This can happen if the debugger is activated and
8166 // the function is returned to the not compiled state.
8167 if (!function->shared()->is_compiled()) {
8168 function->ReplaceCode(function->shared()->code());
8169 return function->code();
8170 }
8171
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008172 // If the function is not optimizable or debugger is active continue using the
8173 // code from the full compiler.
8174 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008175 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008176 if (FLAG_trace_opt) {
8177 PrintF("[failed to optimize ");
8178 function->PrintName();
8179 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8180 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008181 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008182 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008183 function->ReplaceCode(function->shared()->code());
8184 return function->code();
8185 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008186 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008187 return function->code();
8188 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008189 if (FLAG_trace_opt) {
8190 PrintF("[failed to optimize ");
8191 function->PrintName();
8192 PrintF(": optimized compilation failed]\n");
8193 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008194 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008195 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008196}
8197
8198
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008199RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008201 ASSERT(args.length() == 1);
8202 RUNTIME_ASSERT(args[0]->IsSmi());
8203 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008204 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008205 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8206 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008207 int frames = deoptimizer->output_count();
8208
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008209 deoptimizer->MaterializeHeapNumbers();
8210 delete deoptimizer;
8211
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008212 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008213 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008214 for (int i = 0; i < frames - 1; i++) it.Advance();
8215 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008216
8217 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008218 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008219 Handle<Object> arguments;
8220 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008221 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008222 if (arguments.is_null()) {
8223 // FunctionGetArguments can't throw an exception, so cast away the
8224 // doubt with an assert.
8225 arguments = Handle<Object>(
8226 Accessors::FunctionGetArguments(*function,
8227 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008228 ASSERT(*arguments != isolate->heap()->null_value());
8229 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008230 }
8231 frame->SetExpression(i, *arguments);
8232 }
8233 }
8234
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008235 if (type == Deoptimizer::EAGER) {
8236 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008237 }
8238
8239 // Avoid doing too much work when running with --always-opt and keep
8240 // the optimized code around.
8241 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008242 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008243 }
8244
8245 // Count the number of optimized activations of the function.
8246 int activations = 0;
8247 while (!it.done()) {
8248 JavaScriptFrame* frame = it.frame();
8249 if (frame->is_optimized() && frame->function() == *function) {
8250 activations++;
8251 }
8252 it.Advance();
8253 }
8254
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008255 if (activations == 0) {
8256 if (FLAG_trace_deopt) {
8257 PrintF("[removing optimized code for: ");
8258 function->PrintName();
8259 PrintF("]\n");
8260 }
8261 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008262 } else {
8263 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008264 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008265 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008266}
8267
8268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008269RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008270 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008271 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008272 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008273}
8274
8275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008276RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008277 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008278 ASSERT(args.length() == 1);
8279 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008280 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008281
8282 Deoptimizer::DeoptimizeFunction(*function);
8283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008285}
8286
8287
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008288RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8289#if defined(USE_SIMULATOR)
8290 return isolate->heap()->true_value();
8291#else
8292 return isolate->heap()->false_value();
8293#endif
8294}
8295
8296
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008297RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8298 HandleScope scope(isolate);
8299 ASSERT(args.length() == 1);
8300 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8301 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8302 function->MarkForLazyRecompilation();
8303 return isolate->heap()->undefined_value();
8304}
8305
8306
lrn@chromium.org1c092762011-05-09 09:42:16 +00008307RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8308 HandleScope scope(isolate);
8309 ASSERT(args.length() == 1);
8310 if (!V8::UseCrankshaft()) {
8311 return Smi::FromInt(4); // 4 == "never".
8312 }
8313 if (FLAG_always_opt) {
8314 return Smi::FromInt(3); // 3 == "always".
8315 }
8316 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8317 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8318 : Smi::FromInt(2); // 2 == "no".
8319}
8320
8321
8322RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8323 HandleScope scope(isolate);
8324 ASSERT(args.length() == 1);
8325 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8326 return Smi::FromInt(function->shared()->opt_count());
8327}
8328
8329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008330RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008331 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008332 ASSERT(args.length() == 1);
8333 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8334
8335 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008336 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008337
8338 // We have hit a back edge in an unoptimized frame for a function that was
8339 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008340 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008341 // Keep track of whether we've succeeded in optimizing.
8342 bool succeeded = unoptimized->optimizable();
8343 if (succeeded) {
8344 // If we are trying to do OSR when there are already optimized
8345 // activations of the function, it means (a) the function is directly or
8346 // indirectly recursive and (b) an optimized invocation has been
8347 // deoptimized so that we are currently in an unoptimized activation.
8348 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008349 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008350 while (succeeded && !it.done()) {
8351 JavaScriptFrame* frame = it.frame();
8352 succeeded = !frame->is_optimized() || frame->function() != *function;
8353 it.Advance();
8354 }
8355 }
8356
8357 int ast_id = AstNode::kNoNumber;
8358 if (succeeded) {
8359 // The top JS function is this one, the PC is somewhere in the
8360 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008361 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008362 JavaScriptFrame* frame = it.frame();
8363 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008364 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008365 ASSERT(unoptimized->contains(frame->pc()));
8366
8367 // Use linear search of the unoptimized code's stack check table to find
8368 // the AST id matching the PC.
8369 Address start = unoptimized->instruction_start();
8370 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008371 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008372 uint32_t table_length = Memory::uint32_at(table_cursor);
8373 table_cursor += kIntSize;
8374 for (unsigned i = 0; i < table_length; ++i) {
8375 // Table entries are (AST id, pc offset) pairs.
8376 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8377 if (pc_offset == target_pc_offset) {
8378 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8379 break;
8380 }
8381 table_cursor += 2 * kIntSize;
8382 }
8383 ASSERT(ast_id != AstNode::kNoNumber);
8384 if (FLAG_trace_osr) {
8385 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8386 function->PrintName();
8387 PrintF("]\n");
8388 }
8389
8390 // Try to compile the optimized code. A true return value from
8391 // CompileOptimized means that compilation succeeded, not necessarily
8392 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008393 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8394 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008395 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8396 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008397 if (data->OsrPcOffset()->value() >= 0) {
8398 if (FLAG_trace_osr) {
8399 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008400 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008401 }
8402 ASSERT(data->OsrAstId()->value() == ast_id);
8403 } else {
8404 // We may never generate the desired OSR entry if we emit an
8405 // early deoptimize.
8406 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008407 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008408 } else {
8409 succeeded = false;
8410 }
8411 }
8412
8413 // Revert to the original stack checks in the original unoptimized code.
8414 if (FLAG_trace_osr) {
8415 PrintF("[restoring original stack checks in ");
8416 function->PrintName();
8417 PrintF("]\n");
8418 }
8419 StackCheckStub check_stub;
8420 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008421 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008422 Deoptimizer::RevertStackCheckCode(*unoptimized,
8423 *check_code,
8424 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008425
8426 // Allow OSR only at nesting level zero again.
8427 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8428
8429 // If the optimization attempt succeeded, return the AST id tagged as a
8430 // smi. This tells the builtin that we need to translate the unoptimized
8431 // frame to an optimized one.
8432 if (succeeded) {
8433 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8434 return Smi::FromInt(ast_id);
8435 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008436 if (function->IsMarkedForLazyRecompilation()) {
8437 function->ReplaceCode(function->shared()->code());
8438 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008439 return Smi::FromInt(-1);
8440 }
8441}
8442
8443
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008444RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8445 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8446 return isolate->heap()->undefined_value();
8447}
8448
8449
lrn@chromium.org34e60782011-09-15 07:25:40 +00008450RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8451 HandleScope scope(isolate);
8452 ASSERT(args.length() == 5);
8453 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8454 Object* receiver = args[1];
8455 CONVERT_CHECKED(JSObject, arguments, args[2]);
8456 CONVERT_CHECKED(Smi, shift, args[3]);
8457 CONVERT_CHECKED(Smi, arity, args[4]);
8458
8459 int offset = shift->value();
8460 int argc = arity->value();
8461 ASSERT(offset >= 0);
8462 ASSERT(argc >= 0);
8463
8464 // If there are too many arguments, allocate argv via malloc.
8465 const int argv_small_size = 10;
8466 Handle<Object> argv_small_buffer[argv_small_size];
8467 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8468 Handle<Object>* argv = argv_small_buffer;
8469 if (argc > argv_small_size) {
8470 argv = new Handle<Object>[argc];
8471 if (argv == NULL) return isolate->StackOverflow();
8472 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8473 }
8474
8475 for (int i = 0; i < argc; ++i) {
8476 MaybeObject* maybe = arguments->GetElement(offset + i);
8477 Object* object;
8478 if (!maybe->To<Object>(&object)) return maybe;
8479 argv[i] = Handle<Object>(object);
8480 }
8481
8482 bool threw = false;
8483 Handle<JSReceiver> hfun(fun);
8484 Handle<Object> hreceiver(receiver);
8485 Handle<Object> result = Execution::Call(
8486 hfun, hreceiver, argc, reinterpret_cast<Object***>(argv), &threw, true);
8487
8488 if (threw) return Failure::Exception();
8489 return *result;
8490}
8491
8492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008493RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008494 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008495 ASSERT(args.length() == 1);
8496 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8497 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8498}
8499
8500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008501RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008502 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008503 ASSERT(args.length() == 1);
8504 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8505 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8506}
8507
8508
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008509RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008510 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008511 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512
kasper.lund7276f142008-07-30 08:49:36 +00008513 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008514 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008515 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008516 { MaybeObject* maybe_result =
8517 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008518 if (!maybe_result->ToObject(&result)) return maybe_result;
8519 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008520
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008521 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008522
kasper.lund7276f142008-07-30 08:49:36 +00008523 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008524}
8525
lrn@chromium.org303ada72010-10-27 09:33:13 +00008526
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008527RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8528 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008529 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008530 JSObject* extension_object;
8531 if (args[0]->IsJSObject()) {
8532 extension_object = JSObject::cast(args[0]);
8533 } else {
8534 // Convert the object to a proper JavaScript object.
8535 MaybeObject* maybe_js_object = args[0]->ToObject();
8536 if (!maybe_js_object->To(&extension_object)) {
8537 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8538 HandleScope scope(isolate);
8539 Handle<Object> handle = args.at<Object>(0);
8540 Handle<Object> result =
8541 isolate->factory()->NewTypeError("with_expression",
8542 HandleVector(&handle, 1));
8543 return isolate->Throw(*result);
8544 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008545 return maybe_js_object;
8546 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008547 }
8548 }
8549
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008550 JSFunction* function;
8551 if (args[1]->IsSmi()) {
8552 // A smi sentinel indicates a context nested inside global code rather
8553 // than some function. There is a canonical empty function that can be
8554 // gotten from the global context.
8555 function = isolate->context()->global_context()->closure();
8556 } else {
8557 function = JSFunction::cast(args[1]);
8558 }
8559
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008560 Context* context;
8561 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008562 isolate->heap()->AllocateWithContext(function,
8563 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008564 extension_object);
8565 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008566 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008567 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008568}
8569
8570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008571RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008572 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008573 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008574 String* name = String::cast(args[0]);
8575 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008576 JSFunction* function;
8577 if (args[2]->IsSmi()) {
8578 // A smi sentinel indicates a context nested inside global code rather
8579 // than some function. There is a canonical empty function that can be
8580 // gotten from the global context.
8581 function = isolate->context()->global_context()->closure();
8582 } else {
8583 function = JSFunction::cast(args[2]);
8584 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008585 Context* context;
8586 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008587 isolate->heap()->AllocateCatchContext(function,
8588 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008589 name,
8590 thrown_object);
8591 if (!maybe_context->To(&context)) return maybe_context;
8592 isolate->set_context(context);
8593 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008594}
8595
8596
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008597RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8598 NoHandleAllocation ha;
8599 ASSERT(args.length() == 2);
8600 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8601 JSFunction* function;
8602 if (args[1]->IsSmi()) {
8603 // A smi sentinel indicates a context nested inside global code rather
8604 // than some function. There is a canonical empty function that can be
8605 // gotten from the global context.
8606 function = isolate->context()->global_context()->closure();
8607 } else {
8608 function = JSFunction::cast(args[1]);
8609 }
8610 Context* context;
8611 MaybeObject* maybe_context =
8612 isolate->heap()->AllocateBlockContext(function,
8613 isolate->context(),
8614 scope_info);
8615 if (!maybe_context->To(&context)) return maybe_context;
8616 isolate->set_context(context);
8617 return context;
8618}
8619
8620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008621RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008622 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008623 ASSERT(args.length() == 2);
8624
8625 CONVERT_ARG_CHECKED(Context, context, 0);
8626 CONVERT_ARG_CHECKED(String, name, 1);
8627
8628 int index;
8629 PropertyAttributes attributes;
8630 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008631 BindingFlags binding_flags;
8632 Handle<Object> holder = context->Lookup(name,
8633 flags,
8634 &index,
8635 &attributes,
8636 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008637
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008638 // If the slot was not found the result is true.
8639 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008640 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008641 }
8642
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008643 // If the slot was found in a context, it should be DONT_DELETE.
8644 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008645 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008646 }
8647
8648 // The slot was found in a JSObject, either a context extension object,
8649 // the global object, or an arguments object. Try to delete it
8650 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8651 // which allows deleting all parameters in functions that mention
8652 // 'arguments', we do this even for the case of slots found on an
8653 // arguments object. The slot was found on an arguments object if the
8654 // index is non-negative.
8655 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8656 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008657 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008658 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008659 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008660 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008661}
8662
8663
ager@chromium.orga1645e22009-09-09 19:27:10 +00008664// A mechanism to return a pair of Object pointers in registers (if possible).
8665// How this is achieved is calling convention-dependent.
8666// All currently supported x86 compiles uses calling conventions that are cdecl
8667// variants where a 64-bit value is returned in two 32-bit registers
8668// (edx:eax on ia32, r1:r0 on ARM).
8669// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8670// In Win64 calling convention, a struct of two pointers is returned in memory,
8671// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008672#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008673struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008674 MaybeObject* x;
8675 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008676};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008677
lrn@chromium.org303ada72010-10-27 09:33:13 +00008678static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008679 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008680 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8681 // In Win64 they are assigned to a hidden first argument.
8682 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008683}
8684#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008685typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008686static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008688 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008689}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008690#endif
8691
8692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008693static inline MaybeObject* Unhole(Heap* heap,
8694 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008695 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008696 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8697 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008698 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008699}
8700
8701
danno@chromium.org40cb8782011-05-25 07:58:50 +00008702static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8703 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008704 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008705 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008706 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008707 JSFunction* context_extension_function =
8708 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008709 // If the holder isn't a context extension object, we just return it
8710 // as the receiver. This allows arguments objects to be used as
8711 // receivers, but only if they are put in the context scope chain
8712 // explicitly via a with-statement.
8713 Object* constructor = holder->map()->constructor();
8714 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008715 // Fall back to using the global object as the implicit receiver if
8716 // the property turns out to be a local variable allocated in a
8717 // context extension object - introduced via eval. Implicit global
8718 // receivers are indicated with the hole value.
8719 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008720}
8721
8722
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008723static ObjectPair LoadContextSlotHelper(Arguments args,
8724 Isolate* isolate,
8725 bool throw_error) {
8726 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008727 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008728
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008729 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008730 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008732 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008733 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008734
8735 int index;
8736 PropertyAttributes attributes;
8737 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008738 BindingFlags binding_flags;
8739 Handle<Object> holder = context->Lookup(name,
8740 flags,
8741 &index,
8742 &attributes,
8743 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008744
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008745 // If the index is non-negative, the slot has been found in a local
8746 // variable or a parameter. Read it from the context object or the
8747 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008748 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008749 // If the "property" we were looking for is a local variable or an
8750 // argument in a context, the receiver is the global object; see
8751 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008752 //
8753 // Use the hole as the receiver to signal that the receiver is
8754 // implicit and that the global receiver should be used.
8755 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008756 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008757 ? Context::cast(*holder)->get(index)
8758 : JSObject::cast(*holder)->GetElement(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008759 // Check for uninitialized bindings.
8760 if (holder->IsContext() &&
8761 binding_flags == MUTABLE_CHECK_INITIALIZED &&
8762 value->IsTheHole()) {
8763 Handle<Object> reference_error =
8764 isolate->factory()->NewReferenceError("not_defined",
8765 HandleVector(&name, 1));
8766 return MakePair(isolate->Throw(*reference_error), NULL);
8767 } else {
8768 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8769 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008770 }
8771
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008772 // If the holder is found, we read the property from it.
8773 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008774 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008775 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008776 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008777 if (object->IsGlobalObject()) {
8778 receiver = GlobalObject::cast(object)->global_receiver();
8779 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008780 // Use the hole as the receiver to signal that the receiver is
8781 // implicit and that the global receiver should be used.
8782 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008783 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008784 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008785 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008786
8787 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008788 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008789
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008790 // No need to unhole the value here. This is taken care of by the
8791 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008792 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008793 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008794 }
8795
8796 if (throw_error) {
8797 // The property doesn't exist - throw exception.
8798 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008799 isolate->factory()->NewReferenceError("not_defined",
8800 HandleVector(&name, 1));
8801 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008802 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008803 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008804 return MakePair(isolate->heap()->undefined_value(),
8805 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008806 }
8807}
8808
8809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008810RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008811 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008812}
8813
8814
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008815RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008816 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008817}
8818
8819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008820RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008821 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008822 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008823
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008824 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008826 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008827 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008828 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8829 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008830 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008831
8832 int index;
8833 PropertyAttributes attributes;
8834 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008835 BindingFlags binding_flags;
8836 Handle<Object> holder = context->Lookup(name,
8837 flags,
8838 &index,
8839 &attributes,
8840 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008841
8842 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008843 if (holder->IsContext()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008844 Handle<Context> context = Handle<Context>::cast(holder);
8845 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8846 context->get(index)->IsTheHole()) {
8847 Handle<Object> error =
8848 isolate->factory()->NewReferenceError("not_defined",
8849 HandleVector(&name, 1));
8850 return isolate->Throw(*error);
8851 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008852 // Ignore if read_only variable.
8853 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008854 // Context is a fixed array and set cannot fail.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008855 context->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008856 } else if (strict_mode == kStrictMode) {
8857 // Setting read only property in strict mode.
8858 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008859 isolate->factory()->NewTypeError("strict_cannot_assign",
8860 HandleVector(&name, 1));
8861 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008862 }
8863 } else {
8864 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008865 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008866 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008867 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008868 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008869 return Failure::Exception();
8870 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871 }
8872 return *value;
8873 }
8874
8875 // Slow case: The property is not in a FixedArray context.
8876 // It is either in an JSObject extension context or it was not found.
8877 Handle<JSObject> context_ext;
8878
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008879 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008881 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008882 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008883 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008885
8886 if (strict_mode == kStrictMode) {
8887 // Throw in strict mode (assignment to undefined variable).
8888 Handle<Object> error =
8889 isolate->factory()->NewReferenceError(
8890 "not_defined", HandleVector(&name, 1));
8891 return isolate->Throw(*error);
8892 }
8893 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008894 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008895 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008896 }
8897
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008898 // Set the property, but ignore if read_only variable on the context
8899 // extension object itself.
8900 if ((attributes & READ_ONLY) == 0 ||
8901 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008902 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008903 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008904 SetProperty(context_ext, name, value, NONE, strict_mode));
8905 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008906 // Setting read only property in strict mode.
8907 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008908 isolate->factory()->NewTypeError(
8909 "strict_cannot_assign", HandleVector(&name, 1));
8910 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008911 }
8912 return *value;
8913}
8914
8915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008916RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008917 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008918 ASSERT(args.length() == 1);
8919
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008920 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008921}
8922
8923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008924RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008925 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008926 ASSERT(args.length() == 1);
8927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008928 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008929}
8930
8931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008932RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008933 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008934 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008935}
8936
8937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008938RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008939 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940 ASSERT(args.length() == 1);
8941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008942 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008943 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008944 isolate->factory()->NewReferenceError("not_defined",
8945 HandleVector(&name, 1));
8946 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008947}
8948
8949
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008950RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008951 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008952
8953 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008954 if (isolate->stack_guard()->IsStackOverflow()) {
8955 NoHandleAllocation na;
8956 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008958
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008959 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960}
8961
8962
8963// NOTE: These PrintXXX functions are defined for all builds (not just
8964// DEBUG builds) because we may want to be able to trace function
8965// calls in all modes.
8966static void PrintString(String* str) {
8967 // not uncommon to have empty strings
8968 if (str->length() > 0) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008969 SmartArrayPointer<char> s =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8971 PrintF("%s", *s);
8972 }
8973}
8974
8975
8976static void PrintObject(Object* obj) {
8977 if (obj->IsSmi()) {
8978 PrintF("%d", Smi::cast(obj)->value());
8979 } else if (obj->IsString() || obj->IsSymbol()) {
8980 PrintString(String::cast(obj));
8981 } else if (obj->IsNumber()) {
8982 PrintF("%g", obj->Number());
8983 } else if (obj->IsFailure()) {
8984 PrintF("<failure>");
8985 } else if (obj->IsUndefined()) {
8986 PrintF("<undefined>");
8987 } else if (obj->IsNull()) {
8988 PrintF("<null>");
8989 } else if (obj->IsTrue()) {
8990 PrintF("<true>");
8991 } else if (obj->IsFalse()) {
8992 PrintF("<false>");
8993 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008994 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008995 }
8996}
8997
8998
8999static int StackSize() {
9000 int n = 0;
9001 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9002 return n;
9003}
9004
9005
9006static void PrintTransition(Object* result) {
9007 // indentation
9008 { const int nmax = 80;
9009 int n = StackSize();
9010 if (n <= nmax)
9011 PrintF("%4d:%*s", n, n, "");
9012 else
9013 PrintF("%4d:%*s", n, nmax, "...");
9014 }
9015
9016 if (result == NULL) {
9017 // constructor calls
9018 JavaScriptFrameIterator it;
9019 JavaScriptFrame* frame = it.frame();
9020 if (frame->IsConstructor()) PrintF("new ");
9021 // function name
9022 Object* fun = frame->function();
9023 if (fun->IsJSFunction()) {
9024 PrintObject(JSFunction::cast(fun)->shared()->name());
9025 } else {
9026 PrintObject(fun);
9027 }
9028 // function arguments
9029 // (we are intentionally only printing the actually
9030 // supplied parameters, not all parameters required)
9031 PrintF("(this=");
9032 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009033 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009034 for (int i = 0; i < length; i++) {
9035 PrintF(", ");
9036 PrintObject(frame->GetParameter(i));
9037 }
9038 PrintF(") {\n");
9039
9040 } else {
9041 // function result
9042 PrintF("} -> ");
9043 PrintObject(result);
9044 PrintF("\n");
9045 }
9046}
9047
9048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009049RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009050 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009051 NoHandleAllocation ha;
9052 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009053 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009054}
9055
9056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009057RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058 NoHandleAllocation ha;
9059 PrintTransition(args[0]);
9060 return args[0]; // return TOS
9061}
9062
9063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009064RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009065 NoHandleAllocation ha;
9066 ASSERT(args.length() == 1);
9067
9068#ifdef DEBUG
9069 if (args[0]->IsString()) {
9070 // If we have a string, assume it's a code "marker"
9071 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009072 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009073 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009074 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9075 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009076 } else {
9077 PrintF("DebugPrint: ");
9078 }
9079 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009080 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009081 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009082 HeapObject::cast(args[0])->map()->Print();
9083 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009084#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009085 // ShortPrint is available in release mode. Print is not.
9086 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009087#endif
9088 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009089 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009090
9091 return args[0]; // return TOS
9092}
9093
9094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009095RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009096 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009097 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009098 isolate->PrintStack();
9099 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009100}
9101
9102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009103RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009104 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009105 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106
9107 // According to ECMA-262, section 15.9.1, page 117, the precision of
9108 // the number in a Date object representing a particular instant in
9109 // time is milliseconds. Therefore, we floor the result of getting
9110 // the OS time.
9111 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009112 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009113}
9114
9115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009116RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009117 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009118 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009120 CONVERT_ARG_CHECKED(String, str, 0);
9121 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009122
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009123 CONVERT_ARG_CHECKED(JSArray, output, 1);
9124 RUNTIME_ASSERT(output->HasFastElements());
9125
9126 AssertNoAllocation no_allocation;
9127
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009128 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009129 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9130 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009131 String::FlatContent str_content = str->GetFlatContent();
9132 if (str_content.IsAscii()) {
9133 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009134 output_array,
9135 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009136 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009137 ASSERT(str_content.IsTwoByte());
9138 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009139 output_array,
9140 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009141 }
9142
9143 if (result) {
9144 return *output;
9145 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009146 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009147 }
9148}
9149
9150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009151RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009152 NoHandleAllocation ha;
9153 ASSERT(args.length() == 1);
9154
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009155 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009156 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009157 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009158}
9159
9160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009161RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009163 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009164
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009165 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166}
9167
9168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009169RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009170 NoHandleAllocation ha;
9171 ASSERT(args.length() == 1);
9172
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009173 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009174 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175}
9176
9177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009178RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009179 ASSERT(args.length() == 1);
9180 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009181 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009182 return JSGlobalObject::cast(global)->global_receiver();
9183}
9184
9185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009186RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009187 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009188 ASSERT_EQ(1, args.length());
9189 CONVERT_ARG_CHECKED(String, source, 0);
9190
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009191 source = Handle<String>(source->TryFlattenGetString());
9192 // Optimized fast case where we only have ascii characters.
9193 Handle<Object> result;
9194 if (source->IsSeqAsciiString()) {
9195 result = JsonParser<true>::Parse(source);
9196 } else {
9197 result = JsonParser<false>::Parse(source);
9198 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009199 if (result.is_null()) {
9200 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009201 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009202 return Failure::Exception();
9203 }
9204 return *result;
9205}
9206
9207
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009208bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9209 Handle<Context> context) {
9210 if (context->allow_code_gen_from_strings()->IsFalse()) {
9211 // Check with callback if set.
9212 AllowCodeGenerationFromStringsCallback callback =
9213 isolate->allow_code_gen_callback();
9214 if (callback == NULL) {
9215 // No callback set and code generation disallowed.
9216 return false;
9217 } else {
9218 // Callback set. Let it decide if code generation is allowed.
9219 VMState state(isolate, EXTERNAL);
9220 return callback(v8::Utils::ToLocal(context));
9221 }
9222 }
9223 return true;
9224}
9225
9226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009227RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009228 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009229 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009230 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009231
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009232 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009233 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009234
9235 // Check if global context allows code generation from
9236 // strings. Throw an exception if it doesn't.
9237 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9238 return isolate->Throw(*isolate->factory()->NewError(
9239 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9240 }
9241
9242 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009243 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9244 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009245 true,
9246 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009247 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009248 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009249 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9250 context,
9251 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252 return *fun;
9253}
9254
9255
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009256static ObjectPair CompileGlobalEval(Isolate* isolate,
9257 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009258 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009259 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009260 Handle<Context> context = Handle<Context>(isolate->context());
9261 Handle<Context> global_context = Handle<Context>(context->global_context());
9262
9263 // Check if global context allows code generation from
9264 // strings. Throw an exception if it doesn't.
9265 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9266 isolate->Throw(*isolate->factory()->NewError(
9267 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9268 return MakePair(Failure::Exception(), NULL);
9269 }
9270
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009271 // Deal with a normal eval call with a string argument. Compile it
9272 // and return the compiled function bound in the local context.
9273 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9274 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009275 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009276 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009277 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009278 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009279 Handle<JSFunction> compiled =
9280 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009281 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009282 return MakePair(*compiled, *receiver);
9283}
9284
9285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009286RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009287 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009289 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009290 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009291 Handle<Object> receiver; // Will be overwritten.
9292
9293 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009294 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009295#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009296 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009297 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009298 StackFrameLocator locator;
9299 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009300 ASSERT(Context::cast(frame->context()) == *context);
9301#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009302
9303 // Find where the 'eval' symbol is bound. It is unaliased only if
9304 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009305 int index = -1;
9306 PropertyAttributes attributes = ABSENT;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009307 BindingFlags binding_flags;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009308 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009309 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9310 FOLLOW_PROTOTYPE_CHAIN,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009311 &index,
9312 &attributes,
9313 &binding_flags);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009314 // Stop search when eval is found or when the global context is
9315 // reached.
9316 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009317 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009318 }
9319
iposva@chromium.org245aa852009-02-10 00:49:54 +00009320 // If eval could not be resolved, it has been deleted and we need to
9321 // throw a reference error.
9322 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009323 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009324 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009325 isolate->factory()->NewReferenceError("not_defined",
9326 HandleVector(&name, 1));
9327 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009328 }
9329
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009330 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009331 // 'eval' is not bound in the global context. Just call the function
9332 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009333 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009334 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009335 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009336 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009337 }
9338
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009339 // 'eval' is bound in the global context, but it may have been overwritten.
9340 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009341 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009342 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009343 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009344 }
9345
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009346 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 return CompileGlobalEval(isolate,
9348 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009349 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009350 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009351}
9352
9353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009354RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009355 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009356
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009357 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009358 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009359
9360 // 'eval' is bound in the global context, but it may have been overwritten.
9361 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009363 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009364 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009365 }
9366
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009367 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009368 return CompileGlobalEval(isolate,
9369 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009370 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009371 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009372}
9373
9374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009375RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009376 // This utility adjusts the property attributes for newly created Function
9377 // object ("new Function(...)") by changing the map.
9378 // All it does is changing the prototype property to enumerable
9379 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009380 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009381 ASSERT(args.length() == 1);
9382 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009383
9384 Handle<Map> map = func->shared()->strict_mode()
9385 ? isolate->strict_mode_function_instance_map()
9386 : isolate->function_instance_map();
9387
9388 ASSERT(func->map()->instance_type() == map->instance_type());
9389 ASSERT(func->map()->instance_size() == map->instance_size());
9390 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009391 return *func;
9392}
9393
9394
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009395RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009396 // Allocate a block of memory in NewSpace (filled with a filler).
9397 // Use as fallback for allocation in generated code when NewSpace
9398 // is full.
9399 ASSERT(args.length() == 1);
9400 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9401 int size = size_smi->value();
9402 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9403 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009404 Heap* heap = isolate->heap();
9405 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009406 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009407 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009408 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009409 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009410 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009411 }
9412 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009413 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009414}
9415
9416
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009417// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009418// array. Returns true if the element was pushed on the stack and
9419// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009420RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009421 ASSERT(args.length() == 2);
9422 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009423 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009424 RUNTIME_ASSERT(array->HasFastElements());
9425 int length = Smi::cast(array->length())->value();
9426 FixedArray* elements = FixedArray::cast(array->elements());
9427 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009428 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009429 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009430 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009431 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009432 { MaybeObject* maybe_obj =
9433 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009434 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9435 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009437}
9438
9439
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009440/**
9441 * A simple visitor visits every element of Array's.
9442 * The backend storage can be a fixed array for fast elements case,
9443 * or a dictionary for sparse array. Since Dictionary is a subtype
9444 * of FixedArray, the class can be used by both fast and slow cases.
9445 * The second parameter of the constructor, fast_elements, specifies
9446 * whether the storage is a FixedArray or Dictionary.
9447 *
9448 * An index limit is used to deal with the situation that a result array
9449 * length overflows 32-bit non-negative integer.
9450 */
9451class ArrayConcatVisitor {
9452 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009453 ArrayConcatVisitor(Isolate* isolate,
9454 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009455 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009456 isolate_(isolate),
9457 storage_(Handle<FixedArray>::cast(
9458 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009459 index_offset_(0u),
9460 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009461
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009462 ~ArrayConcatVisitor() {
9463 clear_storage();
9464 }
9465
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009466 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009467 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009468 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009469
9470 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009471 if (index < static_cast<uint32_t>(storage_->length())) {
9472 storage_->set(index, *elm);
9473 return;
9474 }
9475 // Our initial estimate of length was foiled, possibly by
9476 // getters on the arrays increasing the length of later arrays
9477 // during iteration.
9478 // This shouldn't happen in anything but pathological cases.
9479 SetDictionaryMode(index);
9480 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009481 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009482 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009483 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009484 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009485 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009486 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009487 // Dictionary needed to grow.
9488 clear_storage();
9489 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009490 }
9491}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009492
9493 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009494 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9495 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009496 } else {
9497 index_offset_ += delta;
9498 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009499 }
9500
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009501 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009502 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009503 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009504 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009505 Handle<Map> map;
9506 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009507 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009508 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009509 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009510 }
9511 array->set_map(*map);
9512 array->set_length(*length);
9513 array->set_elements(*storage_);
9514 return array;
9515 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009516
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009517 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009518 // Convert storage to dictionary mode.
9519 void SetDictionaryMode(uint32_t index) {
9520 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009521 Handle<FixedArray> current_storage(*storage_);
9522 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009523 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009524 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9525 for (uint32_t i = 0; i < current_length; i++) {
9526 HandleScope loop_scope;
9527 Handle<Object> element(current_storage->get(i));
9528 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009529 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009530 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009531 if (!new_storage.is_identical_to(slow_storage)) {
9532 slow_storage = loop_scope.CloseAndEscape(new_storage);
9533 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009534 }
9535 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009536 clear_storage();
9537 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009538 fast_elements_ = false;
9539 }
9540
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009541 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 isolate_->global_handles()->Destroy(
9543 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009544 }
9545
9546 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009547 storage_ = Handle<FixedArray>::cast(
9548 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009549 }
9550
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009551 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009552 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009553 // Index after last seen index. Always less than or equal to
9554 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009555 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009556 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009557};
9558
9559
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009560static uint32_t EstimateElementCount(Handle<JSArray> array) {
9561 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9562 int element_count = 0;
9563 switch (array->GetElementsKind()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009564 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009565 // Fast elements can't have lengths that are not representable by
9566 // a 32-bit signed integer.
9567 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9568 int fast_length = static_cast<int>(length);
9569 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9570 for (int i = 0; i < fast_length; i++) {
9571 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009572 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009573 break;
9574 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009575 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009576 Handle<NumberDictionary> dictionary(
9577 NumberDictionary::cast(array->elements()));
9578 int capacity = dictionary->Capacity();
9579 for (int i = 0; i < capacity; i++) {
9580 Handle<Object> key(dictionary->KeyAt(i));
9581 if (dictionary->IsKey(*key)) {
9582 element_count++;
9583 }
9584 }
9585 break;
9586 }
9587 default:
9588 // External arrays are always dense.
9589 return length;
9590 }
9591 // As an estimate, we assume that the prototype doesn't contain any
9592 // inherited elements.
9593 return element_count;
9594}
9595
9596
9597
9598template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009599static void IterateExternalArrayElements(Isolate* isolate,
9600 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009601 bool elements_are_ints,
9602 bool elements_are_guaranteed_smis,
9603 ArrayConcatVisitor* visitor) {
9604 Handle<ExternalArrayClass> array(
9605 ExternalArrayClass::cast(receiver->elements()));
9606 uint32_t len = static_cast<uint32_t>(array->length());
9607
9608 ASSERT(visitor != NULL);
9609 if (elements_are_ints) {
9610 if (elements_are_guaranteed_smis) {
9611 for (uint32_t j = 0; j < len; j++) {
9612 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009613 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009614 visitor->visit(j, e);
9615 }
9616 } else {
9617 for (uint32_t j = 0; j < len; j++) {
9618 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009619 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009620 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9621 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9622 visitor->visit(j, e);
9623 } else {
9624 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009625 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009626 visitor->visit(j, e);
9627 }
9628 }
9629 }
9630 } else {
9631 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009632 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009633 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009634 visitor->visit(j, e);
9635 }
9636 }
9637}
9638
9639
9640// Used for sorting indices in a List<uint32_t>.
9641static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9642 uint32_t a = *ap;
9643 uint32_t b = *bp;
9644 return (a == b) ? 0 : (a < b) ? -1 : 1;
9645}
9646
9647
9648static void CollectElementIndices(Handle<JSObject> object,
9649 uint32_t range,
9650 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009651 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009652 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009653 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009654 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9655 uint32_t length = static_cast<uint32_t>(elements->length());
9656 if (range < length) length = range;
9657 for (uint32_t i = 0; i < length; i++) {
9658 if (!elements->get(i)->IsTheHole()) {
9659 indices->Add(i);
9660 }
9661 }
9662 break;
9663 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009664 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009665 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009666 uint32_t capacity = dict->Capacity();
9667 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009668 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009669 Handle<Object> k(dict->KeyAt(j));
9670 if (dict->IsKey(*k)) {
9671 ASSERT(k->IsNumber());
9672 uint32_t index = static_cast<uint32_t>(k->Number());
9673 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009674 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009675 }
9676 }
9677 }
9678 break;
9679 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009680 default: {
9681 int dense_elements_length;
9682 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009683 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009684 dense_elements_length =
9685 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009686 break;
9687 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009688 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009689 dense_elements_length =
9690 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009691 break;
9692 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009693 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009694 dense_elements_length =
9695 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009696 break;
9697 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009698 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009699 dense_elements_length =
9700 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009701 break;
9702 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009703 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009704 dense_elements_length =
9705 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009706 break;
9707 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009708 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009709 dense_elements_length =
9710 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009711 break;
9712 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009713 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009714 dense_elements_length =
9715 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009716 break;
9717 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009718 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009719 dense_elements_length =
9720 ExternalFloatArray::cast(object->elements())->length();
9721 break;
9722 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009723 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009724 dense_elements_length =
9725 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009726 break;
9727 }
9728 default:
9729 UNREACHABLE();
9730 dense_elements_length = 0;
9731 break;
9732 }
9733 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9734 if (range <= length) {
9735 length = range;
9736 // We will add all indices, so we might as well clear it first
9737 // and avoid duplicates.
9738 indices->Clear();
9739 }
9740 for (uint32_t i = 0; i < length; i++) {
9741 indices->Add(i);
9742 }
9743 if (length == range) return; // All indices accounted for already.
9744 break;
9745 }
9746 }
9747
9748 Handle<Object> prototype(object->GetPrototype());
9749 if (prototype->IsJSObject()) {
9750 // The prototype will usually have no inherited element indices,
9751 // but we have to check.
9752 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9753 }
9754}
9755
9756
9757/**
9758 * A helper function that visits elements of a JSArray in numerical
9759 * order.
9760 *
9761 * The visitor argument called for each existing element in the array
9762 * with the element index and the element's value.
9763 * Afterwards it increments the base-index of the visitor by the array
9764 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009765 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009766 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009767static bool IterateElements(Isolate* isolate,
9768 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009769 ArrayConcatVisitor* visitor) {
9770 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9771 switch (receiver->GetElementsKind()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009772 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009773 // Run through the elements FixedArray and use HasElement and GetElement
9774 // to check the prototype for missing elements.
9775 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9776 int fast_length = static_cast<int>(length);
9777 ASSERT(fast_length <= elements->length());
9778 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009779 HandleScope loop_scope(isolate);
9780 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009781 if (!element_value->IsTheHole()) {
9782 visitor->visit(j, element_value);
9783 } else if (receiver->HasElement(j)) {
9784 // Call GetElement on receiver, not its prototype, or getters won't
9785 // have the correct receiver.
9786 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009787 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009788 visitor->visit(j, element_value);
9789 }
9790 }
9791 break;
9792 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009793 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009794 Handle<NumberDictionary> dict(receiver->element_dictionary());
9795 List<uint32_t> indices(dict->Capacity() / 2);
9796 // Collect all indices in the object and the prototypes less
9797 // than length. This might introduce duplicates in the indices list.
9798 CollectElementIndices(receiver, length, &indices);
9799 indices.Sort(&compareUInt32);
9800 int j = 0;
9801 int n = indices.length();
9802 while (j < n) {
9803 HandleScope loop_scope;
9804 uint32_t index = indices[j];
9805 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009806 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009807 visitor->visit(index, element);
9808 // Skip to next different index (i.e., omit duplicates).
9809 do {
9810 j++;
9811 } while (j < n && indices[j] == index);
9812 }
9813 break;
9814 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009815 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009816 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9817 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009818 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009819 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009820 visitor->visit(j, e);
9821 }
9822 break;
9823 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009824 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009825 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009826 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009827 break;
9828 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009829 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009830 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009831 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009832 break;
9833 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009834 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009835 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009836 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009837 break;
9838 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009839 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009840 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009841 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009842 break;
9843 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009844 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009845 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009846 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009847 break;
9848 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009849 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009850 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009851 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009852 break;
9853 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009854 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009855 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009856 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009857 break;
9858 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009859 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009860 IterateExternalArrayElements<ExternalDoubleArray, double>(
9861 isolate, receiver, false, false, visitor);
9862 break;
9863 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009864 default:
9865 UNREACHABLE();
9866 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009867 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009868 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009869 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009870}
9871
9872
9873/**
9874 * Array::concat implementation.
9875 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009876 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009877 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009878 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009879RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009880 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009881 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009882
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009883 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9884 int argument_count = static_cast<int>(arguments->length()->Number());
9885 RUNTIME_ASSERT(arguments->HasFastElements());
9886 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009887
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009888 // Pass 1: estimate the length and number of elements of the result.
9889 // The actual length can be larger if any of the arguments have getters
9890 // that mutate other arguments (but will otherwise be precise).
9891 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009892
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009893 uint32_t estimate_result_length = 0;
9894 uint32_t estimate_nof_elements = 0;
9895 {
9896 for (int i = 0; i < argument_count; i++) {
9897 HandleScope loop_scope;
9898 Handle<Object> obj(elements->get(i));
9899 uint32_t length_estimate;
9900 uint32_t element_estimate;
9901 if (obj->IsJSArray()) {
9902 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9903 length_estimate =
9904 static_cast<uint32_t>(array->length()->Number());
9905 element_estimate =
9906 EstimateElementCount(array);
9907 } else {
9908 length_estimate = 1;
9909 element_estimate = 1;
9910 }
9911 // Avoid overflows by capping at kMaxElementCount.
9912 if (JSObject::kMaxElementCount - estimate_result_length <
9913 length_estimate) {
9914 estimate_result_length = JSObject::kMaxElementCount;
9915 } else {
9916 estimate_result_length += length_estimate;
9917 }
9918 if (JSObject::kMaxElementCount - estimate_nof_elements <
9919 element_estimate) {
9920 estimate_nof_elements = JSObject::kMaxElementCount;
9921 } else {
9922 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009923 }
9924 }
9925 }
9926
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009927 // If estimated number of elements is more than half of length, a
9928 // fixed array (fast case) is more time and space-efficient than a
9929 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009930 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009931
9932 Handle<FixedArray> storage;
9933 if (fast_case) {
9934 // The backing storage array must have non-existing elements to
9935 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009936 storage = isolate->factory()->NewFixedArrayWithHoles(
9937 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009938 } else {
9939 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9940 uint32_t at_least_space_for = estimate_nof_elements +
9941 (estimate_nof_elements >> 2);
9942 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009943 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009944 }
9945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009946 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009947
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009948 for (int i = 0; i < argument_count; i++) {
9949 Handle<Object> obj(elements->get(i));
9950 if (obj->IsJSArray()) {
9951 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009953 return Failure::Exception();
9954 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009955 } else {
9956 visitor.visit(0, obj);
9957 visitor.increase_index_offset(1);
9958 }
9959 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009960
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009961 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009962}
9963
9964
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009965// This will not allocate (flatten the string), but it may run
9966// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009967RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009968 NoHandleAllocation ha;
9969 ASSERT(args.length() == 1);
9970
9971 CONVERT_CHECKED(String, string, args[0]);
9972 StringInputBuffer buffer(string);
9973 while (buffer.has_more()) {
9974 uint16_t character = buffer.GetNext();
9975 PrintF("%c", character);
9976 }
9977 return string;
9978}
9979
ager@chromium.org5ec48922009-05-05 07:25:34 +00009980// Moves all own elements of an object, that are below a limit, to positions
9981// starting at zero. All undefined values are placed after non-undefined values,
9982// and are followed by non-existing element. Does not change the length
9983// property.
9984// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009985RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009986 ASSERT(args.length() == 2);
9987 CONVERT_CHECKED(JSObject, object, args[0]);
9988 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9989 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009990}
9991
9992
9993// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009994RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995 ASSERT(args.length() == 2);
9996 CONVERT_CHECKED(JSArray, from, args[0]);
9997 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009998 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009999 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010000 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10001 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010002 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010003 } else if (new_elements->map() ==
10004 isolate->heap()->fixed_double_array_map()) {
10005 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010006 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010007 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010008 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010009 Object* new_map;
10010 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010011 to->set_map(Map::cast(new_map));
10012 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010013 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010014 Object* obj;
10015 { MaybeObject* maybe_obj = from->ResetElements();
10016 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10017 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010018 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010019 return to;
10020}
10021
10022
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010023// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010024RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010025 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010026 CONVERT_CHECKED(JSObject, object, args[0]);
10027 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010028 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010029 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010030 } else if (object->IsJSArray()) {
10031 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010032 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010033 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010034 }
10035}
10036
10037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010038RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010039 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010040
10041 ASSERT_EQ(3, args.length());
10042
ager@chromium.orgac091b72010-05-05 07:34:42 +000010043 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010044 Handle<Object> key1 = args.at<Object>(1);
10045 Handle<Object> key2 = args.at<Object>(2);
10046
10047 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010048 if (!key1->ToArrayIndex(&index1)
10049 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010050 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010051 }
10052
ager@chromium.orgac091b72010-05-05 07:34:42 +000010053 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
10054 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010055 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010056 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010057 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010058
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010059 RETURN_IF_EMPTY_HANDLE(isolate,
10060 SetElement(jsobject, index1, tmp2, kStrictMode));
10061 RETURN_IF_EMPTY_HANDLE(isolate,
10062 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010064 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010065}
10066
10067
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010068// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010069// might have elements. Can either return keys (positive integers) or
10070// intervals (pair of a negative integer (-start-1) followed by a
10071// positive (length)) or undefined values.
10072// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010073RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010074 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010075 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010076 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010077 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010078 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010079 // Create an array and get all the keys into it, then remove all the
10080 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010081 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010082 int keys_length = keys->length();
10083 for (int i = 0; i < keys_length; i++) {
10084 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010085 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010086 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010087 // Zap invalid keys.
10088 keys->set_undefined(i);
10089 }
10090 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010091 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010092 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010093 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010094 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010095 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010096 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010097 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010098 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010099 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010100 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010101 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010104 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105 }
10106}
10107
10108
10109// DefineAccessor takes an optional final argument which is the
10110// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10111// to the way accessors are implemented, it is set for both the getter
10112// and setter on the first call to DefineAccessor and ignored on
10113// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010114RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10116 // Compute attributes.
10117 PropertyAttributes attributes = NONE;
10118 if (args.length() == 5) {
10119 CONVERT_CHECKED(Smi, attrs, args[4]);
10120 int value = attrs->value();
10121 // Only attribute bits should be set.
10122 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10123 attributes = static_cast<PropertyAttributes>(value);
10124 }
10125
10126 CONVERT_CHECKED(JSObject, obj, args[0]);
10127 CONVERT_CHECKED(String, name, args[1]);
10128 CONVERT_CHECKED(Smi, flag, args[2]);
10129 CONVERT_CHECKED(JSFunction, fun, args[3]);
10130 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10131}
10132
10133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010134RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010135 ASSERT(args.length() == 3);
10136 CONVERT_CHECKED(JSObject, obj, args[0]);
10137 CONVERT_CHECKED(String, name, args[1]);
10138 CONVERT_CHECKED(Smi, flag, args[2]);
10139 return obj->LookupAccessor(name, flag->value() == 0);
10140}
10141
10142
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010143#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010144RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010145 ASSERT(args.length() == 0);
10146 return Execution::DebugBreakHelper();
10147}
10148
10149
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010150// Helper functions for wrapping and unwrapping stack frame ids.
10151static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010152 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010153 return Smi::FromInt(id >> 2);
10154}
10155
10156
10157static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10158 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10159}
10160
10161
10162// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010163// args[0]: debug event listener function to set or null or undefined for
10164// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010166RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010168 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10169 args[0]->IsUndefined() ||
10170 args[0]->IsNull());
10171 Handle<Object> callback = args.at<Object>(0);
10172 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010173 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010174
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010175 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010176}
10177
10178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010179RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010180 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010181 isolate->stack_guard()->DebugBreak();
10182 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010183}
10184
10185
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010186static MaybeObject* DebugLookupResultValue(Heap* heap,
10187 Object* receiver,
10188 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010189 LookupResult* result,
10190 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010191 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010192 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010193 case NORMAL:
10194 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010195 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010196 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010197 }
10198 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010199 case FIELD:
10200 value =
10201 JSObject::cast(
10202 result->holder())->FastPropertyAt(result->GetFieldIndex());
10203 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010204 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010205 }
10206 return value;
10207 case CONSTANT_FUNCTION:
10208 return result->GetConstantFunction();
10209 case CALLBACKS: {
10210 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010211 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010212 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010213 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010214 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010215 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010216 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010217 maybe_value = heap->isolate()->pending_exception();
10218 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010219 if (caught_exception != NULL) {
10220 *caught_exception = true;
10221 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010222 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010223 }
10224 return value;
10225 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010226 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010227 }
10228 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010229 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010230 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010231 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010232 case CONSTANT_TRANSITION:
10233 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010234 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010235 default:
10236 UNREACHABLE();
10237 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010238 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010239 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240}
10241
10242
ager@chromium.org32912102009-01-16 10:38:43 +000010243// Get debugger related details for an object property.
10244// args[0]: object holding property
10245// args[1]: name of the property
10246//
10247// The array returned contains the following information:
10248// 0: Property value
10249// 1: Property details
10250// 2: Property value is exception
10251// 3: Getter function if defined
10252// 4: Setter function if defined
10253// Items 2-4 are only filled if the property has either a getter or a setter
10254// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010255RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010256 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257
10258 ASSERT(args.length() == 2);
10259
10260 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10261 CONVERT_ARG_CHECKED(String, name, 1);
10262
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010263 // Make sure to set the current context to the context before the debugger was
10264 // entered (if the debugger is entered). The reason for switching context here
10265 // is that for some property lookups (accessors and interceptors) callbacks
10266 // into the embedding application can occour, and the embedding application
10267 // could have the assumption that its own global context is the current
10268 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010269 SaveContext save(isolate);
10270 if (isolate->debug()->InDebugger()) {
10271 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010272 }
10273
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010274 // Skip the global proxy as it has no properties and always delegates to the
10275 // real global object.
10276 if (obj->IsJSGlobalProxy()) {
10277 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10278 }
10279
10280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010281 // Check if the name is trivially convertible to an index and get the element
10282 // if so.
10283 uint32_t index;
10284 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010285 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010286 Object* element_or_char;
10287 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010288 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010289 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10290 return maybe_element_or_char;
10291 }
10292 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010293 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010295 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 }
10297
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010298 // Find the number of objects making up this.
10299 int length = LocalPrototypeChainLength(*obj);
10300
10301 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010302 Handle<JSObject> jsproto = obj;
10303 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010304 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010305 jsproto->LocalLookup(*name, &result);
10306 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010307 // LookupResult is not GC safe as it holds raw object pointers.
10308 // GC can happen later in this code so put the required fields into
10309 // local variables using handles when required for later use.
10310 PropertyType result_type = result.type();
10311 Handle<Object> result_callback_obj;
10312 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010313 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10314 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010315 }
10316 Smi* property_details = result.GetPropertyDetails().AsSmi();
10317 // DebugLookupResultValue can cause GC so details from LookupResult needs
10318 // to be copied to handles before this.
10319 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010320 Object* raw_value;
10321 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010322 DebugLookupResultValue(isolate->heap(), *obj, *name,
10323 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010324 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10325 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010326 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010327
10328 // If the callback object is a fixed array then it contains JavaScript
10329 // getter and/or setter.
10330 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10331 result_callback_obj->IsFixedArray();
10332 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010333 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010334 details->set(0, *value);
10335 details->set(1, property_details);
10336 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010337 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010338 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10339 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10340 }
10341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010342 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010343 }
10344 if (i < length - 1) {
10345 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10346 }
10347 }
10348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010349 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350}
10351
10352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010353RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010354 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010355
10356 ASSERT(args.length() == 2);
10357
10358 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10359 CONVERT_ARG_CHECKED(String, name, 1);
10360
10361 LookupResult result;
10362 obj->Lookup(*name, &result);
10363 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010364 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010366 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010367}
10368
10369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010370// Return the property type calculated from the property details.
10371// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010372RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010373 ASSERT(args.length() == 1);
10374 CONVERT_CHECKED(Smi, details, args[0]);
10375 PropertyType type = PropertyDetails(details).type();
10376 return Smi::FromInt(static_cast<int>(type));
10377}
10378
10379
10380// Return the property attribute calculated from the property details.
10381// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010382RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010383 ASSERT(args.length() == 1);
10384 CONVERT_CHECKED(Smi, details, args[0]);
10385 PropertyAttributes attributes = PropertyDetails(details).attributes();
10386 return Smi::FromInt(static_cast<int>(attributes));
10387}
10388
10389
10390// Return the property insertion index calculated from the property details.
10391// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010392RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010393 ASSERT(args.length() == 1);
10394 CONVERT_CHECKED(Smi, details, args[0]);
10395 int index = PropertyDetails(details).index();
10396 return Smi::FromInt(index);
10397}
10398
10399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400// Return property value from named interceptor.
10401// args[0]: object
10402// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010403RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010404 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010405 ASSERT(args.length() == 2);
10406 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10407 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10408 CONVERT_ARG_CHECKED(String, name, 1);
10409
10410 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010411 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010412}
10413
10414
10415// Return element value from indexed interceptor.
10416// args[0]: object
10417// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010418RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010419 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010420 ASSERT(args.length() == 2);
10421 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10422 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10423 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10424
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010425 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010426}
10427
10428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010429RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430 ASSERT(args.length() >= 1);
10431 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010432 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010433 if (isolate->debug()->break_id() == 0 ||
10434 break_id != isolate->debug()->break_id()) {
10435 return isolate->Throw(
10436 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010437 }
10438
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010439 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010440}
10441
10442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010443RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010444 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010445 ASSERT(args.length() == 1);
10446
10447 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010448 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010449 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10450 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010451 if (!maybe_result->ToObject(&result)) return maybe_result;
10452 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010453
10454 // Count all frames which are relevant to debugging stack trace.
10455 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010456 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010457 if (id == StackFrame::NO_ID) {
10458 // If there is no JavaScript stack frame count is 0.
10459 return Smi::FromInt(0);
10460 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010461
10462 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10463 n += it.frame()->GetInlineCount();
10464 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010465 return Smi::FromInt(n);
10466}
10467
10468
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010469class FrameInspector {
10470 public:
10471 FrameInspector(JavaScriptFrame* frame,
10472 int inlined_frame_index,
10473 Isolate* isolate)
10474 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10475 // Calculate the deoptimized frame.
10476 if (frame->is_optimized()) {
10477 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10478 frame, inlined_frame_index, isolate);
10479 }
10480 has_adapted_arguments_ = frame_->has_adapted_arguments();
10481 is_optimized_ = frame_->is_optimized();
10482 }
10483
10484 ~FrameInspector() {
10485 // Get rid of the calculated deoptimized frame if any.
10486 if (deoptimized_frame_ != NULL) {
10487 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10488 isolate_);
10489 }
10490 }
10491
10492 int GetParametersCount() {
10493 return is_optimized_
10494 ? deoptimized_frame_->parameters_count()
10495 : frame_->ComputeParametersCount();
10496 }
10497 int expression_count() { return deoptimized_frame_->expression_count(); }
10498 Object* GetFunction() {
10499 return is_optimized_
10500 ? deoptimized_frame_->GetFunction()
10501 : frame_->function();
10502 }
10503 Object* GetParameter(int index) {
10504 return is_optimized_
10505 ? deoptimized_frame_->GetParameter(index)
10506 : frame_->GetParameter(index);
10507 }
10508 Object* GetExpression(int index) {
10509 return is_optimized_
10510 ? deoptimized_frame_->GetExpression(index)
10511 : frame_->GetExpression(index);
10512 }
10513
10514 // To inspect all the provided arguments the frame might need to be
10515 // replaced with the arguments frame.
10516 void SetArgumentsFrame(JavaScriptFrame* frame) {
10517 ASSERT(has_adapted_arguments_);
10518 frame_ = frame;
10519 is_optimized_ = frame_->is_optimized();
10520 ASSERT(!is_optimized_);
10521 }
10522
10523 private:
10524 JavaScriptFrame* frame_;
10525 DeoptimizedFrameInfo* deoptimized_frame_;
10526 Isolate* isolate_;
10527 bool is_optimized_;
10528 bool has_adapted_arguments_;
10529
10530 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10531};
10532
10533
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534static const int kFrameDetailsFrameIdIndex = 0;
10535static const int kFrameDetailsReceiverIndex = 1;
10536static const int kFrameDetailsFunctionIndex = 2;
10537static const int kFrameDetailsArgumentCountIndex = 3;
10538static const int kFrameDetailsLocalCountIndex = 4;
10539static const int kFrameDetailsSourcePositionIndex = 5;
10540static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010541static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010542static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010543static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010544
10545// Return an array with frame details
10546// args[0]: number: break id
10547// args[1]: number: frame index
10548//
10549// The array returned contains the following information:
10550// 0: Frame id
10551// 1: Receiver
10552// 2: Function
10553// 3: Argument count
10554// 4: Local count
10555// 5: Source position
10556// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010557// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010558// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010559// Arguments name, value
10560// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010561// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010562RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010563 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010564 ASSERT(args.length() == 2);
10565
10566 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010567 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010568 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10569 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010570 if (!maybe_check->ToObject(&check)) return maybe_check;
10571 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010573 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574
10575 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010576 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010577 if (id == StackFrame::NO_ID) {
10578 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010579 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010580 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010581
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010582 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010583
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010585 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010587 if (index < count + it.frame()->GetInlineCount()) break;
10588 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010590 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010592 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010593 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010594 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010595 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010596 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010597
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010598 // Traverse the saved contexts chain to find the active context for the
10599 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010600 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010601 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010602 save = save->prev();
10603 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010604 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010605
10606 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010608
10609 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010610 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010611 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010613 // Check for constructor frame. Inlined frames cannot be construct calls.
10614 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010615 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010616 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010617
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010618 // Get scope info and read from it for local variable information.
10619 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010620 Handle<SharedFunctionInfo> shared(function->shared());
10621 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010622 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010623 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010624
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010625 // Get the locals names and values into a temporary array.
10626 //
10627 // TODO(1240907): Hide compiler-introduced stack variables
10628 // (e.g. .result)? For users of the debugger, they will probably be
10629 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010630 Handle<FixedArray> locals =
10631 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010632
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010633 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010634 int i = 0;
10635 for (; i < info.number_of_stack_slots(); ++i) {
10636 // Use the value from the stack.
10637 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010638 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010639 }
10640 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010641 // Get the context containing declarations.
10642 Handle<Context> context(
10643 Context::cast(it.frame()->context())->declaration_context());
10644 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010645 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010646 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010647 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010648 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010649 }
10650 }
10651
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010652 // Check whether this frame is positioned at return. If not top
10653 // frame or if the frame is optimized it cannot be at a return.
10654 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010655 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010656 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010657 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010658
10659 // If positioned just before return find the value to be returned and add it
10660 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010661 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010662 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010663 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010664 Address internal_frame_sp = NULL;
10665 while (!it2.done()) {
10666 if (it2.frame()->is_internal()) {
10667 internal_frame_sp = it2.frame()->sp();
10668 } else {
10669 if (it2.frame()->is_java_script()) {
10670 if (it2.frame()->id() == it.frame()->id()) {
10671 // The internal frame just before the JavaScript frame contains the
10672 // value to return on top. A debug break at return will create an
10673 // internal frame to store the return value (eax/rax/r0) before
10674 // entering the debug break exit frame.
10675 if (internal_frame_sp != NULL) {
10676 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010677 Handle<Object>(Memory::Object_at(internal_frame_sp),
10678 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010679 break;
10680 }
10681 }
10682 }
10683
10684 // Indicate that the previous frame was not an internal frame.
10685 internal_frame_sp = NULL;
10686 }
10687 it2.Advance();
10688 }
10689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690
10691 // Now advance to the arguments adapter frame (if any). It contains all
10692 // the provided parameters whereas the function frame always have the number
10693 // of arguments matching the functions parameters. The rest of the
10694 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010695 if (it.frame()->has_adapted_arguments()) {
10696 it.AdvanceToArgumentsFrame();
10697 frame_inspector.SetArgumentsFrame(it.frame());
10698 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010699
10700 // Find the number of arguments to fill. At least fill the number of
10701 // parameters for the function and fill more if more parameters are provided.
10702 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010703 if (argument_count < frame_inspector.GetParametersCount()) {
10704 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010705 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010706#ifdef DEBUG
10707 if (it.frame()->is_optimized()) {
10708 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10709 }
10710#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010711
10712 // Calculate the size of the result.
10713 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010714 2 * (argument_count + info.NumberOfLocals()) +
10715 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010716 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010717
10718 // Add the frame id.
10719 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10720
10721 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010722 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010723
10724 // Add the arguments count.
10725 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10726
10727 // Add the locals count
10728 details->set(kFrameDetailsLocalCountIndex,
10729 Smi::FromInt(info.NumberOfLocals()));
10730
10731 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010732 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010733 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10734 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010735 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010736 }
10737
10738 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010739 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010740
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010741 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010742 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010743
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010744 // Add flags to indicate information on whether this frame is
10745 // bit 0: invoked in the debugger context.
10746 // bit 1: optimized frame.
10747 // bit 2: inlined in optimized frame
10748 int flags = 0;
10749 if (*save->context() == *isolate->debug()->debug_context()) {
10750 flags |= 1 << 0;
10751 }
10752 if (it.frame()->is_optimized()) {
10753 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010754 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010755 }
10756 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010757
10758 // Fill the dynamic part.
10759 int details_index = kFrameDetailsFirstDynamicIndex;
10760
10761 // Add arguments name and value.
10762 for (int i = 0; i < argument_count; i++) {
10763 // Name of the argument.
10764 if (i < info.number_of_parameters()) {
10765 details->set(details_index++, *info.parameter_name(i));
10766 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010767 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768 }
10769
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010770 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010771 if (i < it.frame()->ComputeParametersCount()) {
10772 // Get the value from the stack.
10773 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010775 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776 }
10777 }
10778
10779 // Add locals name and value from the temporary copy from the function frame.
10780 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10781 details->set(details_index++, locals->get(i));
10782 }
10783
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010784 // Add the value being returned.
10785 if (at_return) {
10786 details->set(details_index++, *return_value);
10787 }
10788
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010789 // Add the receiver (same as in function frame).
10790 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10791 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010792 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010793 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10794 // If the receiver is not a JSObject and the function is not a
10795 // builtin or strict-mode we have hit an optimization where a
10796 // value object is not converted into a wrapped JS objects. To
10797 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010798 // by creating correct wrapper object based on the calling frame's
10799 // global context.
10800 it.Advance();
10801 Handle<Context> calling_frames_global_context(
10802 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010803 receiver =
10804 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010805 }
10806 details->set(kFrameDetailsReceiverIndex, *receiver);
10807
10808 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010809 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010810}
10811
10812
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010813// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010814static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010815 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010816 Handle<SerializedScopeInfo> serialized_scope_info,
10817 ScopeInfo<>& scope_info,
10818 Handle<Context> context,
10819 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010820 // Fill all context locals to the context extension.
10821 for (int i = Context::MIN_CONTEXT_SLOTS;
10822 i < scope_info.number_of_context_slots();
10823 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010824 int context_index = serialized_scope_info->ContextSlotIndex(
10825 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010826
whesse@chromium.org7b260152011-06-20 15:33:18 +000010827 RETURN_IF_EMPTY_HANDLE_VALUE(
10828 isolate,
10829 SetProperty(scope_object,
10830 scope_info.context_slot_name(i),
10831 Handle<Object>(context->get(context_index), isolate),
10832 NONE,
10833 kNonStrictMode),
10834 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010835 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010836
10837 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010838}
10839
10840
10841// Create a plain JSObject which materializes the local scope for the specified
10842// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010843static Handle<JSObject> MaterializeLocalScope(
10844 Isolate* isolate,
10845 JavaScriptFrame* frame,
10846 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010847 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010848 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010849 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10850 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010851 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010852
10853 // Allocate and initialize a JSObject with all the arguments, stack locals
10854 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010855 Handle<JSObject> local_scope =
10856 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010857
10858 // First fill all parameters.
10859 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010860 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010861 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010862 SetProperty(local_scope,
10863 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010864 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010865 NONE,
10866 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010867 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010868 }
10869
10870 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010871 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010872 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010873 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010874 SetProperty(local_scope,
10875 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010876 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010877 NONE,
10878 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010879 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010880 }
10881
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010882 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10883 // Third fill all context locals.
10884 Handle<Context> frame_context(Context::cast(frame->context()));
10885 Handle<Context> function_context(frame_context->declaration_context());
10886 if (!CopyContextLocalsToScopeObject(isolate,
10887 serialized_scope_info, scope_info,
10888 function_context, local_scope)) {
10889 return Handle<JSObject>();
10890 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010891
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010892 // Finally copy any properties from the function context extension.
10893 // These will be variables introduced by eval.
10894 if (function_context->closure() == *function) {
10895 if (function_context->has_extension() &&
10896 !function_context->IsGlobalContext()) {
10897 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10898 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10899 for (int i = 0; i < keys->length(); i++) {
10900 // Names of variables introduced by eval are strings.
10901 ASSERT(keys->get(i)->IsString());
10902 Handle<String> key(String::cast(keys->get(i)));
10903 RETURN_IF_EMPTY_HANDLE_VALUE(
10904 isolate,
10905 SetProperty(local_scope,
10906 key,
10907 GetProperty(ext, key),
10908 NONE,
10909 kNonStrictMode),
10910 Handle<JSObject>());
10911 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010912 }
10913 }
10914 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010915
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010916 return local_scope;
10917}
10918
10919
10920// Create a plain JSObject which materializes the closure content for the
10921// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10923 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010924 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010925
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010926 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010927 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10928 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010929
10930 // Allocate and initialize a JSObject with all the content of theis function
10931 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010932 Handle<JSObject> closure_scope =
10933 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010934
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010935 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010936 if (!CopyContextLocalsToScopeObject(isolate,
10937 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010938 context, closure_scope)) {
10939 return Handle<JSObject>();
10940 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010941
10942 // Finally copy any properties from the function context extension. This will
10943 // be variables introduced by eval.
10944 if (context->has_extension()) {
10945 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010946 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010947 for (int i = 0; i < keys->length(); i++) {
10948 // Names of variables introduced by eval are strings.
10949 ASSERT(keys->get(i)->IsString());
10950 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010951 RETURN_IF_EMPTY_HANDLE_VALUE(
10952 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010953 SetProperty(closure_scope,
10954 key,
10955 GetProperty(ext, key),
10956 NONE,
10957 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010958 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010959 }
10960 }
10961
10962 return closure_scope;
10963}
10964
10965
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010966// Create a plain JSObject which materializes the scope for the specified
10967// catch context.
10968static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10969 Handle<Context> context) {
10970 ASSERT(context->IsCatchContext());
10971 Handle<String> name(String::cast(context->extension()));
10972 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10973 Handle<JSObject> catch_scope =
10974 isolate->factory()->NewJSObject(isolate->object_function());
10975 RETURN_IF_EMPTY_HANDLE_VALUE(
10976 isolate,
10977 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10978 Handle<JSObject>());
10979 return catch_scope;
10980}
10981
10982
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010983// Create a plain JSObject which materializes the block scope for the specified
10984// block context.
10985static Handle<JSObject> MaterializeBlockScope(
10986 Isolate* isolate,
10987 Handle<Context> context) {
10988 ASSERT(context->IsBlockContext());
10989 Handle<SerializedScopeInfo> serialized_scope_info(
10990 SerializedScopeInfo::cast(context->extension()));
10991 ScopeInfo<> scope_info(*serialized_scope_info);
10992
10993 // Allocate and initialize a JSObject with all the arguments, stack locals
10994 // heap locals and extension properties of the debugged function.
10995 Handle<JSObject> block_scope =
10996 isolate->factory()->NewJSObject(isolate->object_function());
10997
10998 // Fill all context locals.
10999 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
11000 if (!CopyContextLocalsToScopeObject(isolate,
11001 serialized_scope_info, scope_info,
11002 context, block_scope)) {
11003 return Handle<JSObject>();
11004 }
11005 }
11006
11007 return block_scope;
11008}
11009
11010
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011011// Iterate over the actual scopes visible from a stack frame. All scopes are
11012// backed by an actual context except the local scope, which is inserted
11013// "artifically" in the context chain.
11014class ScopeIterator {
11015 public:
11016 enum ScopeType {
11017 ScopeTypeGlobal = 0,
11018 ScopeTypeLocal,
11019 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011020 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011021 ScopeTypeCatch,
11022 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011023 };
11024
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011025 ScopeIterator(Isolate* isolate,
11026 JavaScriptFrame* frame,
11027 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011028 : isolate_(isolate),
11029 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011030 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011031 function_(JSFunction::cast(frame->function())),
11032 context_(Context::cast(frame->context())),
11033 local_done_(false),
11034 at_local_(false) {
11035
11036 // Check whether the first scope is actually a local scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011037 // If there is a stack slot for .result then this local scope has been
11038 // created for evaluating top level code and it is not a real local scope.
11039 // Checking for the existence of .result seems fragile, but the scope info
11040 // saved with the code object does not otherwise have that information.
11041 int index = function_->shared()->scope_info()->
11042 StackSlotIndex(isolate_->heap()->result_symbol());
11043 if (index >= 0) {
11044 local_done_ = true;
11045 } else if (context_->IsGlobalContext() ||
11046 context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011047 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011048 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011049 // The context_ is a block or with or catch block from the outer function.
11050 ASSERT(context_->IsWithContext() ||
11051 context_->IsCatchContext() ||
11052 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011053 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011054 }
11055 }
11056
11057 // More scopes?
11058 bool Done() { return context_.is_null(); }
11059
11060 // Move to the next scope.
11061 void Next() {
11062 // If at a local scope mark the local scope as passed.
11063 if (at_local_) {
11064 at_local_ = false;
11065 local_done_ = true;
11066
11067 // If the current context is not associated with the local scope the
11068 // current context is the next real scope, so don't move to the next
11069 // context in this case.
11070 if (context_->closure() != *function_) {
11071 return;
11072 }
11073 }
11074
11075 // The global scope is always the last in the chain.
11076 if (context_->IsGlobalContext()) {
11077 context_ = Handle<Context>();
11078 return;
11079 }
11080
11081 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011082 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011083
11084 // If passing the local scope indicate that the current scope is now the
11085 // local scope.
11086 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011087 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011088 at_local_ = true;
11089 }
11090 }
11091
11092 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011093 ScopeType Type() {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011094 if (at_local_) {
11095 return ScopeTypeLocal;
11096 }
11097 if (context_->IsGlobalContext()) {
11098 ASSERT(context_->global()->IsGlobalObject());
11099 return ScopeTypeGlobal;
11100 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011101 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011102 return ScopeTypeClosure;
11103 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011104 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011105 return ScopeTypeCatch;
11106 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011107 if (context_->IsBlockContext()) {
11108 return ScopeTypeBlock;
11109 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011110 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011111 return ScopeTypeWith;
11112 }
11113
11114 // Return the JavaScript object with the content of the current scope.
11115 Handle<JSObject> ScopeObject() {
11116 switch (Type()) {
11117 case ScopeIterator::ScopeTypeGlobal:
11118 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011119 case ScopeIterator::ScopeTypeLocal:
11120 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011121 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011122 case ScopeIterator::ScopeTypeWith:
11123 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011124 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11125 case ScopeIterator::ScopeTypeCatch:
11126 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011127 case ScopeIterator::ScopeTypeClosure:
11128 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011129 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011130 case ScopeIterator::ScopeTypeBlock:
11131 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011132 }
11133 UNREACHABLE();
11134 return Handle<JSObject>();
11135 }
11136
11137 // Return the context for this scope. For the local context there might not
11138 // be an actual context.
11139 Handle<Context> CurrentContext() {
11140 if (at_local_ && context_->closure() != *function_) {
11141 return Handle<Context>();
11142 }
11143 return context_;
11144 }
11145
11146#ifdef DEBUG
11147 // Debug print of the content of the current scope.
11148 void DebugPrint() {
11149 switch (Type()) {
11150 case ScopeIterator::ScopeTypeGlobal:
11151 PrintF("Global:\n");
11152 CurrentContext()->Print();
11153 break;
11154
11155 case ScopeIterator::ScopeTypeLocal: {
11156 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011157 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011158 scope_info.Print();
11159 if (!CurrentContext().is_null()) {
11160 CurrentContext()->Print();
11161 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011162 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011163 if (extension->IsJSContextExtensionObject()) {
11164 extension->Print();
11165 }
11166 }
11167 }
11168 break;
11169 }
11170
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011171 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011172 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011173 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011174 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011175
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011176 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011177 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011178 CurrentContext()->extension()->Print();
11179 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011180 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011181
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011182 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011183 PrintF("Closure:\n");
11184 CurrentContext()->Print();
11185 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011186 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011187 if (extension->IsJSContextExtensionObject()) {
11188 extension->Print();
11189 }
11190 }
11191 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011192
11193 default:
11194 UNREACHABLE();
11195 }
11196 PrintF("\n");
11197 }
11198#endif
11199
11200 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011201 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011202 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011203 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011204 Handle<JSFunction> function_;
11205 Handle<Context> context_;
11206 bool local_done_;
11207 bool at_local_;
11208
11209 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11210};
11211
11212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011213RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011214 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011215 ASSERT(args.length() == 2);
11216
11217 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011218 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011219 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11220 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011221 if (!maybe_check->ToObject(&check)) return maybe_check;
11222 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011223 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11224
11225 // Get the frame where the debugging is performed.
11226 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011227 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011228 JavaScriptFrame* frame = it.frame();
11229
11230 // Count the visible scopes.
11231 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011232 for (ScopeIterator it(isolate, frame, 0);
11233 !it.Done();
11234 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011235 n++;
11236 }
11237
11238 return Smi::FromInt(n);
11239}
11240
11241
11242static const int kScopeDetailsTypeIndex = 0;
11243static const int kScopeDetailsObjectIndex = 1;
11244static const int kScopeDetailsSize = 2;
11245
11246// Return an array with scope details
11247// args[0]: number: break id
11248// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011249// args[2]: number: inlined frame index
11250// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011251//
11252// The array returned contains the following information:
11253// 0: Scope type
11254// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011255RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011256 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011257 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011258
11259 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011260 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011261 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11262 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011263 if (!maybe_check->ToObject(&check)) return maybe_check;
11264 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011265 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011266 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11267 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011268
11269 // Get the frame where the debugging is performed.
11270 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011271 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011272 JavaScriptFrame* frame = frame_it.frame();
11273
11274 // Find the requested scope.
11275 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011276 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011277 for (; !it.Done() && n < index; it.Next()) {
11278 n++;
11279 }
11280 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011281 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011282 }
11283
11284 // Calculate the size of the result.
11285 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011286 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011287
11288 // Fill in scope details.
11289 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011290 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011291 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011292 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011294 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011295}
11296
11297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011298RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011299 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011300 ASSERT(args.length() == 0);
11301
11302#ifdef DEBUG
11303 // Print the scopes for the top frame.
11304 StackFrameLocator locator;
11305 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011306 for (ScopeIterator it(isolate, frame, 0);
11307 !it.Done();
11308 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011309 it.DebugPrint();
11310 }
11311#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011312 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011313}
11314
11315
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011316RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011317 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011318 ASSERT(args.length() == 1);
11319
11320 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011321 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011322 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11323 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011324 if (!maybe_result->ToObject(&result)) return maybe_result;
11325 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011326
11327 // Count all archived V8 threads.
11328 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011329 for (ThreadState* thread =
11330 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011331 thread != NULL;
11332 thread = thread->Next()) {
11333 n++;
11334 }
11335
11336 // Total number of threads is current thread and archived threads.
11337 return Smi::FromInt(n + 1);
11338}
11339
11340
11341static const int kThreadDetailsCurrentThreadIndex = 0;
11342static const int kThreadDetailsThreadIdIndex = 1;
11343static const int kThreadDetailsSize = 2;
11344
11345// Return an array with thread details
11346// args[0]: number: break id
11347// args[1]: number: thread index
11348//
11349// The array returned contains the following information:
11350// 0: Is current thread?
11351// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011352RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011353 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011354 ASSERT(args.length() == 2);
11355
11356 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011357 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011358 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11359 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011360 if (!maybe_check->ToObject(&check)) return maybe_check;
11361 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011362 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11363
11364 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011365 Handle<FixedArray> details =
11366 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011367
11368 // Thread index 0 is current thread.
11369 if (index == 0) {
11370 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011371 details->set(kThreadDetailsCurrentThreadIndex,
11372 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011373 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011374 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011375 } else {
11376 // Find the thread with the requested index.
11377 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011378 ThreadState* thread =
11379 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011380 while (index != n && thread != NULL) {
11381 thread = thread->Next();
11382 n++;
11383 }
11384 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011385 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011386 }
11387
11388 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011389 details->set(kThreadDetailsCurrentThreadIndex,
11390 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011391 details->set(kThreadDetailsThreadIdIndex,
11392 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011393 }
11394
11395 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011396 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011397}
11398
11399
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011400// Sets the disable break state
11401// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011402RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011403 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011404 ASSERT(args.length() == 1);
11405 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011406 isolate->debug()->set_disable_break(disable_break);
11407 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011408}
11409
11410
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011411RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011412 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011413 ASSERT(args.length() == 1);
11414
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011415 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11416 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011417 // Find the number of break points
11418 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011419 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011420 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011421 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011422 Handle<FixedArray>::cast(break_locations));
11423}
11424
11425
11426// Set a break point in a function
11427// args[0]: function
11428// args[1]: number: break source position (within the function source)
11429// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011430RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011431 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011432 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011433 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11434 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011435 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11436 RUNTIME_ASSERT(source_position >= 0);
11437 Handle<Object> break_point_object_arg = args.at<Object>(2);
11438
11439 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011440 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11441 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011442
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011443 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011444}
11445
11446
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011447Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11448 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011449 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011450 // Iterate the heap looking for SharedFunctionInfo generated from the
11451 // script. The inner most SharedFunctionInfo containing the source position
11452 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011453 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011454 // which is found is not compiled it is compiled and the heap is iterated
11455 // again as the compilation might create inner functions from the newly
11456 // compiled function and the actual requested break point might be in one of
11457 // these functions.
11458 bool done = false;
11459 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011460 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011461 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011462 while (!done) {
11463 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011464 for (HeapObject* obj = iterator.next();
11465 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011466 if (obj->IsSharedFunctionInfo()) {
11467 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11468 if (shared->script() == *script) {
11469 // If the SharedFunctionInfo found has the requested script data and
11470 // contains the source position it is a candidate.
11471 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011472 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011473 start_position = shared->start_position();
11474 }
11475 if (start_position <= position &&
11476 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011477 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011478 // candidate this is the new candidate.
11479 if (target.is_null()) {
11480 target_start_position = start_position;
11481 target = shared;
11482 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011483 if (target_start_position == start_position &&
11484 shared->end_position() == target->end_position()) {
11485 // If a top-level function contain only one function
11486 // declartion the source for the top-level and the function is
11487 // the same. In that case prefer the non top-level function.
11488 if (!shared->is_toplevel()) {
11489 target_start_position = start_position;
11490 target = shared;
11491 }
11492 } else if (target_start_position <= start_position &&
11493 shared->end_position() <= target->end_position()) {
11494 // This containment check includes equality as a function inside
11495 // a top-level function can share either start or end position
11496 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011497 target_start_position = start_position;
11498 target = shared;
11499 }
11500 }
11501 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011502 }
11503 }
11504 }
11505
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011506 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011507 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011508 }
11509
11510 // If the candidate found is compiled we are done. NOTE: when lazy
11511 // compilation of inner functions is introduced some additional checking
11512 // needs to be done here to compile inner functions.
11513 done = target->is_compiled();
11514 if (!done) {
11515 // If the candidate is not compiled compile it to reveal any inner
11516 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011517 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011518 }
11519 }
11520
11521 return *target;
11522}
11523
11524
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011525// Changes the state of a break point in a script and returns source position
11526// where break point was set. NOTE: Regarding performance see the NOTE for
11527// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011528// args[0]: script to set break point in
11529// args[1]: number: break source position (within the script source)
11530// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011531RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011532 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011533 ASSERT(args.length() == 3);
11534 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11535 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11536 RUNTIME_ASSERT(source_position >= 0);
11537 Handle<Object> break_point_object_arg = args.at<Object>(2);
11538
11539 // Get the script from the script wrapper.
11540 RUNTIME_ASSERT(wrapper->value()->IsScript());
11541 Handle<Script> script(Script::cast(wrapper->value()));
11542
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011543 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011544 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011545 if (!result->IsUndefined()) {
11546 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11547 // Find position within function. The script position might be before the
11548 // source position of the first function.
11549 int position;
11550 if (shared->start_position() > source_position) {
11551 position = 0;
11552 } else {
11553 position = source_position - shared->start_position();
11554 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011555 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011556 position += shared->start_position();
11557 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011558 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011559 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011560}
11561
11562
11563// Clear a break point
11564// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011565RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011566 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011567 ASSERT(args.length() == 1);
11568 Handle<Object> break_point_object_arg = args.at<Object>(0);
11569
11570 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011571 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011572
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011573 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011574}
11575
11576
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011577// Change the state of break on exceptions.
11578// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11579// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011580RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011581 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011582 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011583 RUNTIME_ASSERT(args[0]->IsNumber());
11584 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011585
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011586 // If the number doesn't match an enum value, the ChangeBreakOnException
11587 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011588 ExceptionBreakType type =
11589 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011590 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011591 isolate->debug()->ChangeBreakOnException(type, enable);
11592 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011593}
11594
11595
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011596// Returns the state of break on exceptions
11597// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011598RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011599 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011600 ASSERT(args.length() == 1);
11601 RUNTIME_ASSERT(args[0]->IsNumber());
11602
11603 ExceptionBreakType type =
11604 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011606 return Smi::FromInt(result);
11607}
11608
11609
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011610// Prepare for stepping
11611// args[0]: break id for checking execution state
11612// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011613// args[2]: number of times to perform the step, for step out it is the number
11614// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011615RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011616 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011617 ASSERT(args.length() == 3);
11618 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011619 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011620 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11621 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011622 if (!maybe_check->ToObject(&check)) return maybe_check;
11623 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011624 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011626 }
11627
11628 // Get the step action and check validity.
11629 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11630 if (step_action != StepIn &&
11631 step_action != StepNext &&
11632 step_action != StepOut &&
11633 step_action != StepInMin &&
11634 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011635 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011636 }
11637
11638 // Get the number of steps.
11639 int step_count = NumberToInt32(args[2]);
11640 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011641 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011642 }
11643
ager@chromium.orga1645e22009-09-09 19:27:10 +000011644 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011645 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011646
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011648 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11649 step_count);
11650 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011651}
11652
11653
11654// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011655RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011656 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011657 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011658 isolate->debug()->ClearStepping();
11659 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011660}
11661
11662
11663// Creates a copy of the with context chain. The copy of the context chain is
11664// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011665static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011666 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011667 Handle<Context> current,
11668 Handle<Context> base) {
11669 // At the end of the chain. Return the base context to link to.
11670 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11671 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672 }
11673
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011674 // Recursively copy the with and catch contexts.
11675 HandleScope scope(isolate);
11676 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011677 Handle<Context> new_previous =
11678 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011679 Handle<Context> new_current;
11680 if (current->IsCatchContext()) {
11681 Handle<String> name(String::cast(current->extension()));
11682 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11683 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011684 isolate->factory()->NewCatchContext(function,
11685 new_previous,
11686 name,
11687 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011688 } else if (current->IsBlockContext()) {
11689 Handle<SerializedScopeInfo> scope_info(
11690 SerializedScopeInfo::cast(current->extension()));
11691 new_current =
11692 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011693 // Copy context slots.
11694 int num_context_slots = scope_info->NumberOfContextSlots();
11695 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11696 new_current->set(i, current->get(i));
11697 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011698 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011699 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011700 Handle<JSObject> extension(JSObject::cast(current->extension()));
11701 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011702 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011703 }
11704 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011705}
11706
11707
11708// Helper function to find or create the arguments object for
11709// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011710static Handle<Object> GetArgumentsObject(Isolate* isolate,
11711 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011712 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011713 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011714 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011715 const ScopeInfo<>* sinfo,
11716 Handle<Context> function_context) {
11717 // Try to find the value of 'arguments' to pass as parameter. If it is not
11718 // found (that is the debugged function does not reference 'arguments' and
11719 // does not support eval) then create an 'arguments' object.
11720 int index;
11721 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011722 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011723 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011724 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011725 }
11726 }
11727
11728 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011729 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11730 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011731 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011732 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011733 }
11734 }
11735
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011736 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11737
11738 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011739 Handle<JSObject> arguments =
11740 isolate->factory()->NewArgumentsObject(function, length);
11741 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011742
11743 AssertNoAllocation no_gc;
11744 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011745 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011746 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011747 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011748 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011749 return arguments;
11750}
11751
11752
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011753static const char kSourceStr[] =
11754 "(function(arguments,__source__){return eval(__source__);})";
11755
11756
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011757// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011758// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011759// extension part has all the parameters and locals of the function on the
11760// stack frame. A function which calls eval with the code to evaluate is then
11761// compiled in this context and called in this context. As this context
11762// replaces the context of the function on the stack frame a new (empty)
11763// function is created as well to be used as the closure for the context.
11764// This function and the context acts as replacements for the function on the
11765// stack frame presenting the same view of the values of parameters and
11766// local variables as if the piece of JavaScript was evaluated at the point
11767// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011768RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011769 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011770
11771 // Check the execution state and decode arguments frame and source to be
11772 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011773 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011774 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011775 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11776 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011777 if (!maybe_check_result->ToObject(&check_result)) {
11778 return maybe_check_result;
11779 }
11780 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011781 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011782 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11783 CONVERT_ARG_CHECKED(String, source, 3);
11784 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11785 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011786
11787 // Handle the processing of break.
11788 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789
11790 // Get the frame where the debugging is performed.
11791 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011792 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011793 JavaScriptFrame* frame = it.frame();
11794 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011795 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011796 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797
11798 // Traverse the saved contexts chain to find the active context for the
11799 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011800 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011801 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011802 save = save->prev();
11803 }
11804 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011805 SaveContext savex(isolate);
11806 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011807
11808 // Create the (empty) function replacing the function on the stack frame for
11809 // the purpose of evaluating in the context created below. It is important
11810 // that this function does not describe any parameters and local variables
11811 // in the context. If it does then this will cause problems with the lookup
11812 // in Context::Lookup, where context slots for parameters and local variables
11813 // are looked at before the extension object.
11814 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011815 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11816 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011817 go_between->set_context(function->context());
11818#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011819 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011820 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11821 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11822#endif
11823
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011824 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011825 Handle<JSObject> local_scope = MaterializeLocalScope(
11826 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011827 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011828
11829 // Allocate a new context for the debug evaluation and set the extension
11830 // object build.
11831 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11833 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011834 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011835 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011836 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011837 Handle<Context> function_context;
11838 // Get the function's context if it has one.
11839 if (scope_info->HasHeapAllocatedLocals()) {
11840 function_context = Handle<Context>(frame_context->declaration_context());
11841 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011842 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011843
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011844 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011845 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011846 context =
11847 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011848 }
11849
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011850 // Wrap the evaluation statement in a new function compiled in the newly
11851 // created context. The function has one parameter which has to be called
11852 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011853 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011854 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011855
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011856 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011857 isolate->factory()->NewStringFromAscii(
11858 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011859
11860 // Currently, the eval code will be executed in non-strict mode,
11861 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011862 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011863 Compiler::CompileEval(function_source,
11864 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011865 context->IsGlobalContext(),
11866 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011867 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011868 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011869 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011870
11871 // Invoke the result of the compilation to get the evaluation function.
11872 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011873 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011874 Handle<Object> evaluation_function =
11875 Execution::Call(compiled_function, receiver, 0, NULL,
11876 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011877 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011878
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011879 Handle<Object> arguments = GetArgumentsObject(isolate,
11880 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011881 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011882 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883
11884 // Invoke the evaluation function and return the result.
11885 const int argc = 2;
11886 Object** argv[argc] = { arguments.location(),
11887 Handle<Object>::cast(source).location() };
11888 Handle<Object> result =
11889 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11890 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011891 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011892
11893 // Skip the global proxy as it has no properties and always delegates to the
11894 // real global object.
11895 if (result->IsJSGlobalProxy()) {
11896 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11897 }
11898
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011899 return *result;
11900}
11901
11902
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011903RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011904 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011905
11906 // Check the execution state and decode arguments frame and source to be
11907 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011908 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011909 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011910 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11911 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011912 if (!maybe_check_result->ToObject(&check_result)) {
11913 return maybe_check_result;
11914 }
11915 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011916 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011917 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011918 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011919
11920 // Handle the processing of break.
11921 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011922
11923 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011924 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011925 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011926 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011927 top = top->prev();
11928 }
11929 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011930 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011931 }
11932
11933 // Get the global context now set to the top context from before the
11934 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011935 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011936
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011937 bool is_global = true;
11938
11939 if (additional_context->IsJSObject()) {
11940 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011941 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11942 isolate->factory()->empty_string(),
11943 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011944 go_between->set_context(*context);
11945 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011946 isolate->factory()->NewFunctionContext(
11947 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011948 context->set_extension(JSObject::cast(*additional_context));
11949 is_global = false;
11950 }
11951
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011952 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011953 // Currently, the eval code will be executed in non-strict mode,
11954 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011955 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011956 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011957 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011958 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011959 Handle<JSFunction>(
11960 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11961 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011962
11963 // Invoke the result of the compilation to get the evaluation function.
11964 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011965 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011966 Handle<Object> result =
11967 Execution::Call(compiled_function, receiver, 0, NULL,
11968 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011969 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011970 return *result;
11971}
11972
11973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011974RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011975 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011976 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011977
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011978 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011979 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011980
11981 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011982 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011983 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11984 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11985 // because using
11986 // instances->set(i, *GetScriptWrapper(script))
11987 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11988 // already have deferenced the instances handle.
11989 Handle<JSValue> wrapper = GetScriptWrapper(script);
11990 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011991 }
11992
11993 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011994 Handle<JSObject> result =
11995 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011996 Handle<JSArray>::cast(result)->SetContent(*instances);
11997 return *result;
11998}
11999
12000
12001// Helper function used by Runtime_DebugReferencedBy below.
12002static int DebugReferencedBy(JSObject* target,
12003 Object* instance_filter, int max_references,
12004 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012005 JSFunction* arguments_function) {
12006 NoHandleAllocation ha;
12007 AssertNoAllocation no_alloc;
12008
12009 // Iterate the heap.
12010 int count = 0;
12011 JSObject* last = NULL;
12012 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012013 HeapObject* heap_obj = NULL;
12014 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012015 (max_references == 0 || count < max_references)) {
12016 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012017 if (heap_obj->IsJSObject()) {
12018 // Skip context extension objects and argument arrays as these are
12019 // checked in the context of functions using them.
12020 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012021 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012022 obj->map()->constructor() == arguments_function) {
12023 continue;
12024 }
12025
12026 // Check if the JS object has a reference to the object looked for.
12027 if (obj->ReferencesObject(target)) {
12028 // Check instance filter if supplied. This is normally used to avoid
12029 // references from mirror objects (see Runtime_IsInPrototypeChain).
12030 if (!instance_filter->IsUndefined()) {
12031 Object* V = obj;
12032 while (true) {
12033 Object* prototype = V->GetPrototype();
12034 if (prototype->IsNull()) {
12035 break;
12036 }
12037 if (instance_filter == prototype) {
12038 obj = NULL; // Don't add this object.
12039 break;
12040 }
12041 V = prototype;
12042 }
12043 }
12044
12045 if (obj != NULL) {
12046 // Valid reference found add to instance array if supplied an update
12047 // count.
12048 if (instances != NULL && count < instances_size) {
12049 instances->set(count, obj);
12050 }
12051 last = obj;
12052 count++;
12053 }
12054 }
12055 }
12056 }
12057
12058 // Check for circular reference only. This can happen when the object is only
12059 // referenced from mirrors and has a circular reference in which case the
12060 // object is not really alive and would have been garbage collected if not
12061 // referenced from the mirror.
12062 if (count == 1 && last == target) {
12063 count = 0;
12064 }
12065
12066 // Return the number of referencing objects found.
12067 return count;
12068}
12069
12070
12071// Scan the heap for objects with direct references to an object
12072// args[0]: the object to find references to
12073// args[1]: constructor function for instances to exclude (Mirror)
12074// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012075RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076 ASSERT(args.length() == 3);
12077
12078 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012079 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012080
12081 // Check parameters.
12082 CONVERT_CHECKED(JSObject, target, args[0]);
12083 Object* instance_filter = args[1];
12084 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12085 instance_filter->IsJSObject());
12086 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12087 RUNTIME_ASSERT(max_references >= 0);
12088
12089 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012090 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012091 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012092 JSFunction* arguments_function =
12093 JSFunction::cast(arguments_boilerplate->map()->constructor());
12094
12095 // Get the number of referencing objects.
12096 int count;
12097 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012098 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099
12100 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012101 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012102 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012103 if (!maybe_object->ToObject(&object)) return maybe_object;
12104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012105 FixedArray* instances = FixedArray::cast(object);
12106
12107 // Fill the referencing objects.
12108 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012109 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012110
12111 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012112 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012113 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12114 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012115 if (!maybe_result->ToObject(&result)) return maybe_result;
12116 }
12117 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012118 return result;
12119}
12120
12121
12122// Helper function used by Runtime_DebugConstructedBy below.
12123static int DebugConstructedBy(JSFunction* constructor, int max_references,
12124 FixedArray* instances, int instances_size) {
12125 AssertNoAllocation no_alloc;
12126
12127 // Iterate the heap.
12128 int count = 0;
12129 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012130 HeapObject* heap_obj = NULL;
12131 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012132 (max_references == 0 || count < max_references)) {
12133 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134 if (heap_obj->IsJSObject()) {
12135 JSObject* obj = JSObject::cast(heap_obj);
12136 if (obj->map()->constructor() == constructor) {
12137 // Valid reference found add to instance array if supplied an update
12138 // count.
12139 if (instances != NULL && count < instances_size) {
12140 instances->set(count, obj);
12141 }
12142 count++;
12143 }
12144 }
12145 }
12146
12147 // Return the number of referencing objects found.
12148 return count;
12149}
12150
12151
12152// Scan the heap for objects constructed by a specific function.
12153// args[0]: the constructor to find instances of
12154// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012155RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012156 ASSERT(args.length() == 2);
12157
12158 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012159 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012160
12161 // Check parameters.
12162 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12163 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12164 RUNTIME_ASSERT(max_references >= 0);
12165
12166 // Get the number of referencing objects.
12167 int count;
12168 count = DebugConstructedBy(constructor, max_references, NULL, 0);
12169
12170 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012171 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012172 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012173 if (!maybe_object->ToObject(&object)) return maybe_object;
12174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012175 FixedArray* instances = FixedArray::cast(object);
12176
12177 // Fill the referencing objects.
12178 count = DebugConstructedBy(constructor, max_references, instances, count);
12179
12180 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012181 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012182 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12183 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012184 if (!maybe_result->ToObject(&result)) return maybe_result;
12185 }
12186 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012187 return result;
12188}
12189
12190
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012191// Find the effective prototype object as returned by __proto__.
12192// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012193RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012194 ASSERT(args.length() == 1);
12195
12196 CONVERT_CHECKED(JSObject, obj, args[0]);
12197
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012198 // Use the __proto__ accessor.
12199 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012200}
12201
12202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012203RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012204 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012205 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012206 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012207}
12208
12209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012210RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012211#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012212 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012213 ASSERT(args.length() == 1);
12214 // Get the function and make sure it is compiled.
12215 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012216 Handle<SharedFunctionInfo> shared(func->shared());
12217 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012218 return Failure::Exception();
12219 }
12220 func->code()->PrintLn();
12221#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012222 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012223}
ager@chromium.org9085a012009-05-11 19:22:57 +000012224
12225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012226RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012227#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012228 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012229 ASSERT(args.length() == 1);
12230 // Get the function and make sure it is compiled.
12231 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012232 Handle<SharedFunctionInfo> shared(func->shared());
12233 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012234 return Failure::Exception();
12235 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012236 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012237#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012238 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012239}
12240
12241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012242RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012243 NoHandleAllocation ha;
12244 ASSERT(args.length() == 1);
12245
12246 CONVERT_CHECKED(JSFunction, f, args[0]);
12247 return f->shared()->inferred_name();
12248}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012249
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012250
12251static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012252 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012253 AssertNoAllocation no_allocations;
12254
12255 int counter = 0;
12256 int buffer_size = buffer->length();
12257 HeapIterator iterator;
12258 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
12259 ASSERT(obj != NULL);
12260 if (!obj->IsSharedFunctionInfo()) {
12261 continue;
12262 }
12263 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12264 if (shared->script() != script) {
12265 continue;
12266 }
12267 if (counter < buffer_size) {
12268 buffer->set(counter, shared);
12269 }
12270 counter++;
12271 }
12272 return counter;
12273}
12274
12275// For a script finds all SharedFunctionInfo's in the heap that points
12276// to this script. Returns JSArray of SharedFunctionInfo wrapped
12277// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012278RUNTIME_FUNCTION(MaybeObject*,
12279 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012280 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012281 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012282 CONVERT_CHECKED(JSValue, script_value, args[0]);
12283
12284 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12285
12286 const int kBufferSize = 32;
12287
12288 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012289 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012290 int number = FindSharedFunctionInfosForScript(*script, *array);
12291 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012292 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012293 FindSharedFunctionInfosForScript(*script, *array);
12294 }
12295
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012296 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012297 result->set_length(Smi::FromInt(number));
12298
12299 LiveEdit::WrapSharedFunctionInfos(result);
12300
12301 return *result;
12302}
12303
12304// For a script calculates compilation information about all its functions.
12305// The script source is explicitly specified by the second argument.
12306// The source of the actual script is not used, however it is important that
12307// all generated code keeps references to this particular instance of script.
12308// Returns a JSArray of compilation infos. The array is ordered so that
12309// each function with all its descendant is always stored in a continues range
12310// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012311RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012312 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012313 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012314 CONVERT_CHECKED(JSValue, script, args[0]);
12315 CONVERT_ARG_CHECKED(String, source, 1);
12316 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12317
12318 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12319
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012320 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012321 return Failure::Exception();
12322 }
12323
12324 return result;
12325}
12326
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012327// Changes the source of the script to a new_source.
12328// If old_script_name is provided (i.e. is a String), also creates a copy of
12329// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012330RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012331 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012332 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012333 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12334 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012335 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012336
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012337 CONVERT_CHECKED(Script, original_script_pointer,
12338 original_script_value->value());
12339 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012340
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012341 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12342 new_source,
12343 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012344
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012345 if (old_script->IsScript()) {
12346 Handle<Script> script_handle(Script::cast(old_script));
12347 return *(GetScriptWrapper(script_handle));
12348 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012349 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012350 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012351}
12352
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012354RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012355 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012356 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012357 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12358 return LiveEdit::FunctionSourceUpdated(shared_info);
12359}
12360
12361
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012362// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012363RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012364 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012365 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012366 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12367 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12368
ager@chromium.orgac091b72010-05-05 07:34:42 +000012369 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012370}
12371
12372// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012373RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012374 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012375 HandleScope scope(isolate);
12376 Handle<Object> function_object(args[0], isolate);
12377 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012378
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012379 if (function_object->IsJSValue()) {
12380 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12381 if (script_object->IsJSValue()) {
12382 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012383 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012384 }
12385
12386 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12387 } else {
12388 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12389 // and we check it in this function.
12390 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012391
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012392 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012393}
12394
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012395
12396// In a code of a parent function replaces original function as embedded object
12397// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012398RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012399 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012400 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012401
12402 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12403 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12404 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12405
12406 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12407 subst_wrapper);
12408
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012409 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012410}
12411
12412
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012413// Updates positions of a shared function info (first parameter) according
12414// to script source change. Text change is described in second parameter as
12415// array of groups of 3 numbers:
12416// (change_begin, change_end, change_end_new_position).
12417// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012418RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012419 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012420 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012421 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12422 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12423
ager@chromium.orgac091b72010-05-05 07:34:42 +000012424 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012425}
12426
12427
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012428// For array of SharedFunctionInfo's (each wrapped in JSValue)
12429// checks that none of them have activations on stacks (of any thread).
12430// Returns array of the same length with corresponding results of
12431// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012432RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012433 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012434 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012435 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012436 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012437
ager@chromium.org357bf652010-04-12 11:30:10 +000012438 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012439}
12440
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012441// Compares 2 strings line-by-line, then token-wise and returns diff in form
12442// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12443// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012444RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012445 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012446 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012447 CONVERT_ARG_CHECKED(String, s1, 0);
12448 CONVERT_ARG_CHECKED(String, s2, 1);
12449
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012450 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012451}
12452
12453
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012454// A testing entry. Returns statement position which is the closest to
12455// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012456RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012457 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012458 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012459 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12460 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12461
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012462 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012463
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012464 if (code->kind() != Code::FUNCTION &&
12465 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012466 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012467 }
12468
12469 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012470 int closest_pc = 0;
12471 int distance = kMaxInt;
12472 while (!it.done()) {
12473 int statement_position = static_cast<int>(it.rinfo()->data());
12474 // Check if this break point is closer that what was previously found.
12475 if (source_position <= statement_position &&
12476 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012477 closest_pc =
12478 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012479 distance = statement_position - source_position;
12480 // Check whether we can't get any closer.
12481 if (distance == 0) break;
12482 }
12483 it.next();
12484 }
12485
12486 return Smi::FromInt(closest_pc);
12487}
12488
12489
ager@chromium.org357bf652010-04-12 11:30:10 +000012490// Calls specified function with or without entering the debugger.
12491// This is used in unit tests to run code as if debugger is entered or simply
12492// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012493RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012494 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012496 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12497 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12498
12499 Handle<Object> result;
12500 bool pending_exception;
12501 {
12502 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012503 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012504 &pending_exception);
12505 } else {
12506 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012507 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012508 &pending_exception);
12509 }
12510 }
12511 if (!pending_exception) {
12512 return *result;
12513 } else {
12514 return Failure::Exception();
12515 }
12516}
12517
12518
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012519// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012520RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012521 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012522 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012523 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12524 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012525 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012526}
12527
12528
12529// Performs a GC.
12530// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012531RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012532 isolate->heap()->CollectAllGarbage(true);
12533 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012534}
12535
12536
12537// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012538RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012539 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012540 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012541 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012542 }
12543 return Smi::FromInt(usage);
12544}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012545
12546
12547// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012548RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012549#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012550 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012551#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012552 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012553#endif
12554}
12555
12556
12557// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012558RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012559#ifdef LIVE_OBJECT_LIST
12560 return LiveObjectList::Capture();
12561#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012562 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012563#endif
12564}
12565
12566
12567// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012568RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012569#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012570 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012571 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012572 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012573#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012574 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012575#endif
12576}
12577
12578
12579// Generates the response to a debugger request for a dump of the objects
12580// contained in the difference between the captured live object lists
12581// specified by id1 and id2.
12582// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12583// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012584RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012585#ifdef LIVE_OBJECT_LIST
12586 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012587 CONVERT_SMI_ARG_CHECKED(id1, 0);
12588 CONVERT_SMI_ARG_CHECKED(id2, 1);
12589 CONVERT_SMI_ARG_CHECKED(start, 2);
12590 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012591 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12592 EnterDebugger enter_debugger;
12593 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12594#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012595 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012596#endif
12597}
12598
12599
12600// Gets the specified object as requested by the debugger.
12601// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012602RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012603#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012604 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012605 Object* result = LiveObjectList::GetObj(obj_id);
12606 return result;
12607#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012608 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012609#endif
12610}
12611
12612
12613// Gets the obj id for the specified address if valid.
12614// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012615RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012616#ifdef LIVE_OBJECT_LIST
12617 HandleScope scope;
12618 CONVERT_ARG_CHECKED(String, address, 0);
12619 Object* result = LiveObjectList::GetObjId(address);
12620 return result;
12621#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012622 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012623#endif
12624}
12625
12626
12627// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012628RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012629#ifdef LIVE_OBJECT_LIST
12630 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012631 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012632 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12633 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12634 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12635 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12636 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12637
12638 Handle<JSObject> instance_filter;
12639 if (args[1]->IsJSObject()) {
12640 instance_filter = args.at<JSObject>(1);
12641 }
12642 bool verbose = false;
12643 if (args[2]->IsBoolean()) {
12644 verbose = args[2]->IsTrue();
12645 }
12646 int start = 0;
12647 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012648 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012649 }
12650 int limit = Smi::kMaxValue;
12651 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012652 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012653 }
12654
12655 return LiveObjectList::GetObjRetainers(obj_id,
12656 instance_filter,
12657 verbose,
12658 start,
12659 limit,
12660 filter_obj);
12661#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012662 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012663#endif
12664}
12665
12666
12667// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012668RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012669#ifdef LIVE_OBJECT_LIST
12670 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012671 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12672 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012673 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12674
12675 Handle<JSObject> instance_filter;
12676 if (args[2]->IsJSObject()) {
12677 instance_filter = args.at<JSObject>(2);
12678 }
12679
12680 Object* result =
12681 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12682 return result;
12683#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012684 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012685#endif
12686}
12687
12688
12689// Generates the response to a debugger request for a list of all
12690// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012691RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012692#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012693 CONVERT_SMI_ARG_CHECKED(start, 0);
12694 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012695 return LiveObjectList::Info(start, count);
12696#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012697 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012698#endif
12699}
12700
12701
12702// Gets a dump of the specified object as requested by the debugger.
12703// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012704RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012705#ifdef LIVE_OBJECT_LIST
12706 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012707 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012708 Object* result = LiveObjectList::PrintObj(obj_id);
12709 return result;
12710#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012711 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012712#endif
12713}
12714
12715
12716// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012717RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012718#ifdef LIVE_OBJECT_LIST
12719 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012720 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012721#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012722 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012723#endif
12724}
12725
12726
12727// Generates the response to a debugger request for a summary of the types
12728// of objects in the difference between the captured live object lists
12729// specified by id1 and id2.
12730// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12731// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012732RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012733#ifdef LIVE_OBJECT_LIST
12734 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012735 CONVERT_SMI_ARG_CHECKED(id1, 0);
12736 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012737 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12738
12739 EnterDebugger enter_debugger;
12740 return LiveObjectList::Summarize(id1, id2, filter_obj);
12741#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012742 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012743#endif
12744}
12745
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012746#endif // ENABLE_DEBUGGER_SUPPORT
12747
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012749RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012750 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012751 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012752 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012753}
12754
12755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012756RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012757 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012758 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012759 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012760}
12761
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012762
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012763// Finds the script object from the script data. NOTE: This operation uses
12764// heap traversal to find the function generated for the source position
12765// for the requested break point. For lazily compiled functions several heap
12766// traversals might be required rendering this operation as a rather slow
12767// operation. However for setting break points which is normally done through
12768// some kind of user interaction the performance is not crucial.
12769static Handle<Object> Runtime_GetScriptFromScriptName(
12770 Handle<String> script_name) {
12771 // Scan the heap for Script objects to find the script with the requested
12772 // script data.
12773 Handle<Script> script;
12774 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012775 HeapObject* obj = NULL;
12776 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012777 // If a script is found check if it has the script data requested.
12778 if (obj->IsScript()) {
12779 if (Script::cast(obj)->name()->IsString()) {
12780 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12781 script = Handle<Script>(Script::cast(obj));
12782 }
12783 }
12784 }
12785 }
12786
12787 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012788 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012789
12790 // Return the script found.
12791 return GetScriptWrapper(script);
12792}
12793
12794
12795// Get the script object from script data. NOTE: Regarding performance
12796// see the NOTE for GetScriptFromScriptData.
12797// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012798RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012799 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012800
12801 ASSERT(args.length() == 1);
12802
12803 CONVERT_CHECKED(String, script_name, args[0]);
12804
12805 // Find the requested script.
12806 Handle<Object> result =
12807 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12808 return *result;
12809}
12810
12811
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012812// Determines whether the given stack frame should be displayed in
12813// a stack trace. The caller is the error constructor that asked
12814// for the stack trace to be collected. The first time a construct
12815// call to this function is encountered it is skipped. The seen_caller
12816// in/out parameter is used to remember if the caller has been seen
12817// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012818static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12819 Object* caller,
12820 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012821 // Only display JS frames.
12822 if (!raw_frame->is_java_script())
12823 return false;
12824 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12825 Object* raw_fun = frame->function();
12826 // Not sure when this can happen but skip it just in case.
12827 if (!raw_fun->IsJSFunction())
12828 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012829 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012830 *seen_caller = true;
12831 return false;
12832 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012833 // Skip all frames until we've seen the caller.
12834 if (!(*seen_caller)) return false;
12835 // Also, skip the most obvious builtin calls. We recognize builtins
12836 // as (1) functions called with the builtins object as the receiver and
12837 // as (2) functions from native scripts called with undefined as the
12838 // receiver (direct calls to helper functions in the builtins
12839 // code). Some builtin calls (such as Number.ADD which is invoked
12840 // using 'call') are very difficult to recognize so we're leaving
12841 // them in for now.
12842 if (frame->receiver()->IsJSBuiltinsObject()) {
12843 return false;
12844 }
12845 JSFunction* fun = JSFunction::cast(raw_fun);
12846 Object* raw_script = fun->shared()->script();
12847 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12848 int script_type = Script::cast(raw_script)->type()->value();
12849 return script_type != Script::TYPE_NATIVE;
12850 }
12851 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012852}
12853
12854
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012855// Collect the raw data for a stack trace. Returns an array of 4
12856// element segments each containing a receiver, function, code and
12857// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012858RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012859 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012860 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012861 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12862
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012863 HandleScope scope(isolate);
12864 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012865
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012866 limit = Max(limit, 0); // Ensure that limit is not negative.
12867 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012868 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012869 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012870
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012871 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012872 // If the caller parameter is a function we skip frames until we're
12873 // under it before starting to collect.
12874 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012875 int cursor = 0;
12876 int frames_seen = 0;
12877 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012878 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012879 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012880 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012881 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012882 // Set initial size to the maximum inlining level + 1 for the outermost
12883 // function.
12884 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012885 frame->Summarize(&frames);
12886 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012887 if (cursor + 4 > elements->length()) {
12888 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12889 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012890 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012891 for (int i = 0; i < cursor; i++) {
12892 new_elements->set(i, elements->get(i));
12893 }
12894 elements = new_elements;
12895 }
12896 ASSERT(cursor + 4 <= elements->length());
12897
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012898 Handle<Object> recv = frames[i].receiver();
12899 Handle<JSFunction> fun = frames[i].function();
12900 Handle<Code> code = frames[i].code();
12901 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012902 elements->set(cursor++, *recv);
12903 elements->set(cursor++, *fun);
12904 elements->set(cursor++, *code);
12905 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012906 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012907 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012908 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012909 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012910 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012911 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012912 return *result;
12913}
12914
12915
ager@chromium.org3811b432009-10-28 14:53:37 +000012916// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012917RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012918 ASSERT_EQ(args.length(), 0);
12919
12920 NoHandleAllocation ha;
12921
12922 const char* version_string = v8::V8::GetVersion();
12923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012924 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12925 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012926}
12927
12928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012929RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012930 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012931 OS::PrintError("abort: %s\n",
12932 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012933 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012934 OS::Abort();
12935 UNREACHABLE();
12936 return NULL;
12937}
12938
12939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012940RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012941 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012942 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012943 Object* key = args[1];
12944
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012945 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012946 Object* o = cache->get(finger_index);
12947 if (o == key) {
12948 // The fastest case: hit the same place again.
12949 return cache->get(finger_index + 1);
12950 }
12951
12952 for (int i = finger_index - 2;
12953 i >= JSFunctionResultCache::kEntriesIndex;
12954 i -= 2) {
12955 o = cache->get(i);
12956 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012957 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012958 return cache->get(i + 1);
12959 }
12960 }
12961
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012962 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012963 ASSERT(size <= cache->length());
12964
12965 for (int i = size - 2; i > finger_index; i -= 2) {
12966 o = cache->get(i);
12967 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012968 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012969 return cache->get(i + 1);
12970 }
12971 }
12972
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012973 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012974 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012975
12976 Handle<JSFunctionResultCache> cache_handle(cache);
12977 Handle<Object> key_handle(key);
12978 Handle<Object> value;
12979 {
12980 Handle<JSFunction> factory(JSFunction::cast(
12981 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12982 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012983 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012984 // This handle is nor shared, nor used later, so it's safe.
12985 Object** argv[] = { key_handle.location() };
12986 bool pending_exception = false;
12987 value = Execution::Call(factory,
12988 receiver,
12989 1,
12990 argv,
12991 &pending_exception);
12992 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012993 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012994
12995#ifdef DEBUG
12996 cache_handle->JSFunctionResultCacheVerify();
12997#endif
12998
12999 // Function invocation may have cleared the cache. Reread all the data.
13000 finger_index = cache_handle->finger_index();
13001 size = cache_handle->size();
13002
13003 // If we have spare room, put new data into it, otherwise evict post finger
13004 // entry which is likely to be the least recently used.
13005 int index = -1;
13006 if (size < cache_handle->length()) {
13007 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13008 index = size;
13009 } else {
13010 index = finger_index + JSFunctionResultCache::kEntrySize;
13011 if (index == cache_handle->length()) {
13012 index = JSFunctionResultCache::kEntriesIndex;
13013 }
13014 }
13015
13016 ASSERT(index % 2 == 0);
13017 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13018 ASSERT(index < cache_handle->length());
13019
13020 cache_handle->set(index, *key_handle);
13021 cache_handle->set(index + 1, *value);
13022 cache_handle->set_finger_index(index);
13023
13024#ifdef DEBUG
13025 cache_handle->JSFunctionResultCacheVerify();
13026#endif
13027
13028 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013029}
13030
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013032RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013033 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013034 CONVERT_ARG_CHECKED(String, type, 0);
13035 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013036 return *isolate->factory()->NewJSMessageObject(
13037 type,
13038 arguments,
13039 0,
13040 0,
13041 isolate->factory()->undefined_value(),
13042 isolate->factory()->undefined_value(),
13043 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013044}
13045
13046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013047RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013048 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13049 return message->type();
13050}
13051
13052
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013053RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013054 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13055 return message->arguments();
13056}
13057
13058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013059RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013060 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13061 return Smi::FromInt(message->start_position());
13062}
13063
13064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013065RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013066 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13067 return message->script();
13068}
13069
13070
kasper.lund44510672008-07-25 07:37:58 +000013071#ifdef DEBUG
13072// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13073// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013074RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013075 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013076 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013077#define COUNT_ENTRY(Name, argc, ressize) + 1
13078 int entry_count = 0
13079 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13080 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13081 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13082#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013083 Factory* factory = isolate->factory();
13084 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013085 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013086 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013087#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013088 { \
13089 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013090 Handle<String> name; \
13091 /* Inline runtime functions have an underscore in front of the name. */ \
13092 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013093 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013094 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13095 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013096 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013097 Vector<const char>(#Name, StrLength(#Name))); \
13098 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013099 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013100 pair_elements->set(0, *name); \
13101 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013102 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013103 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013104 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013105 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013106 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013107 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013108 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013109 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013110#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013111 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013112 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013113 return *result;
13114}
kasper.lund44510672008-07-25 07:37:58 +000013115#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013116
13117
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013118RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013119 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013120 CONVERT_CHECKED(String, format, args[0]);
13121 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013122 String::FlatContent format_content = format->GetFlatContent();
13123 RUNTIME_ASSERT(format_content.IsAscii());
13124 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013125 LOGGER->LogRuntime(chars, elms);
13126 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013127}
13128
13129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013130RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013131 UNREACHABLE(); // implemented as macro in the parser
13132 return NULL;
13133}
13134
13135
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013136#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13137 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13138 CONVERT_CHECKED(JSObject, obj, args[0]); \
13139 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13140 }
13141
13142ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13143ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13144ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13145ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13146ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13147ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13148ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13149ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13150ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13151ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13152ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13153ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13154ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13155
13156#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013158// ----------------------------------------------------------------------------
13159// Implementation of Runtime
13160
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013161#define F(name, number_of_args, result_size) \
13162 { Runtime::k##name, Runtime::RUNTIME, #name, \
13163 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013164
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013165
13166#define I(name, number_of_args, result_size) \
13167 { Runtime::kInline##name, Runtime::INLINE, \
13168 "_" #name, NULL, number_of_args, result_size },
13169
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013170static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013171 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013172 INLINE_FUNCTION_LIST(I)
13173 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013174};
13175
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013176
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013177MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13178 Object* dictionary) {
13179 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013180 ASSERT(dictionary != NULL);
13181 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13182 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013183 Object* name_symbol;
13184 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013185 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013186 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13187 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013188 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013189 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13190 String::cast(name_symbol),
13191 Smi::FromInt(i),
13192 PropertyDetails(NONE, NORMAL));
13193 if (!maybe_dictionary->ToObject(&dictionary)) {
13194 // Non-recoverable failure. Calling code must restart heap
13195 // initialization.
13196 return maybe_dictionary;
13197 }
13198 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013199 }
13200 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013201}
13202
13203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013204const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13205 Heap* heap = name->GetHeap();
13206 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013207 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013208 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013209 int function_index = Smi::cast(smi_index)->value();
13210 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013211 }
13212 return NULL;
13213}
13214
13215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013216const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013217 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13218}
13219
13220
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013221void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013222 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013223 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013224 if (failure->IsRetryAfterGC()) {
13225 // Try to do a garbage collection; ignore it if it fails. The C
13226 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013227 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013228 } else {
13229 // Handle last resort GC and make sure to allow future allocations
13230 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013231 isolate->counters()->gc_last_resort_from_js()->Increment();
13232 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013233 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013234}
13235
13236
13237} } // namespace v8::internal